Kotlin新式管道Channel融合flow流,协程实现Android废弃的AsyncTaskLoader(B)

Kotlin新式管道Channel融合flow流,协程实现Android废弃的AsyncTaskLoader(B)

测试运行效果的方法:

Kotlin 复制代码
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking


fun main() {
    val TAG = "main"

    runBlocking {
        val dvm = MyDVM()

        dvm.dataChange(object : DataCallback<String>() {
            override fun onDataChange(old: String?, new: String?) {
                println("收到 old=$old new=$new")
            }
        })

        async(Loader.THREAD_POOL) {
            repeat(5) {
                println("--")
                println("$TAG startLoad $it ${Thread.currentThread().name}")

                dvm.mLoader?.startLoad()
                delay(3000)
            }
        }
    }
}

以下是实现的主体架构:

Kotlin 复制代码
open class DataCallback<D> {
    open fun onDataChange(old: D?, new: D?) {

    }
}
Kotlin 复制代码
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.receiveAsFlow

open class DVModel<D, L : Loader<D>> {
    private val TAG = "DVModel"

    val mLiveData = LiveData<D>()
    var mLoader: L? = null

    constructor() {
        println("$TAG constructor")
        mLoader = getLoader() as L

        CoroutineScope(Loader.THREAD_POOL).async {
            mLoader?.mResultChannel?.receiveAsFlow()?.collect {
                mLiveData.value = it as D
            }
        }
    }

    fun dataChange(callback: DataCallback<D>?) {
        mLiveData.onChange(callback)
    }

    open fun getLoader(): Loader<D>? {
        TODO()
    }
}
Kotlin 复制代码
import kotlin.properties.Delegates
import kotlin.reflect.KProperty

class LiveData<D> {
    private val TAG: String = "LiveData"

    private var mDataCallback: DataCallback<D>? = null

    var value: D? by Delegates.observable(
        initialValue = null,

        onChange = { prop: KProperty<*>, oldVal: D?, newVal: D? ->
            mDataCallback?.onDataChange(oldVal, newVal)
        }
    )

    fun onChange(callback: DataCallback<D>?) {
        mDataCallback = callback
    }
}
Kotlin 复制代码
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onEmpty
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.runBlocking

open class Loader<D> {
    companion object {
        const val TAG = "Loader"

        val THREAD_POOL = newFixedThreadPoolContext(nThreads = 4, name = "my-thread")
    }

    val mResultChannel = Channel<D?>()

    val mTaskChannel = Channel<Msg?>()

    private var mTask: Job?

    constructor() {
        println("$TAG constructor")

        mTask = CoroutineScope(THREAD_POOL).async {
            mTaskChannel.receiveAsFlow()
                .onStart { println("onStart") }
                .onCompletion { println("onCompletion") }
                .onEmpty { println("onEmpty") }
                .onEach {}.flowOn(THREAD_POOL)
                .collect {
                    async(THREAD_POOL) {
                        val result = loadInBackground()
                        mResultChannel.send(result)
                    }
                }

            mTaskChannel.invokeOnClose {
                println("$TAG invokeOnClose")
            }
        }
    }

    open fun loadInBackground(): D? {
        return TODO("")
    }

    fun startLoad() {
        runBlocking {
            async(THREAD_POOL) {
                mTaskChannel.send(Msg())
            }
        }
    }

    private fun stopTask() {
        mTask?.cancel(CancellationException(""))
    }

    fun close() {
        mTaskChannel.close()
        mResultChannel.close()

        stopTask()
    }

    class Msg {
        val timestamp = System.currentTimeMillis()
    }
}

上面是基础框架。下面是开发者需要根据自身业务定制开发的内容:

Kotlin 复制代码
class MyDVM : DVModel<String, Loader<String>> {
    private val TAG = "MyDVM"

    constructor() {
        println("$TAG constructor")
    }

    override fun getLoader(): Loader<String>? {
        return MyLoader()
    }
}
Kotlin 复制代码
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking

class MyLoader : Loader<String> {
    private val TAG = "MyLoader"

    constructor() {
        println("$TAG constructor")
    }

    //假设这里是耗时加载任务
    override fun loadInBackground(): String {
        val result = "Hello,world! ${System.currentTimeMillis()}"

        runBlocking {
            println("$TAG loadInBackground ... ${Thread.currentThread().name}")
            delay(2000)
            println("$TAG loadInBackground done ${Thread.currentThread().name}")
        }

        return result
    }
}

运行输出:

DVModel constructor

Loader constructor

MyLoader constructor

MyDVM constructor

--

main startLoad 0 my-thread-3

onStart

MyLoader loadInBackground ... my-thread-4

MyLoader loadInBackground done my-thread-4

收到 old=null new=Hello,world! 1766975534036

--

main startLoad 1 my-thread-1

MyLoader loadInBackground ... my-thread-3

MyLoader loadInBackground done my-thread-3

收到 old=Hello,world! 1766975534036 new=Hello,world! 1766975537049

--

main startLoad 2 my-thread-3

MyLoader loadInBackground ... my-thread-4

MyLoader loadInBackground done my-thread-4

收到 old=Hello,world! 1766975537049 new=Hello,world! 1766975540054

--

main startLoad 3 my-thread-3

MyLoader loadInBackground ... my-thread-4

MyLoader loadInBackground done my-thread-4

收到 old=Hello,world! 1766975540054 new=Hello,world! 1766975543063

--

main startLoad 4 my-thread-4

MyLoader loadInBackground ... my-thread-1

MyLoader loadInBackground done my-thread-1

收到 old=Hello,world! 1766975543063 new=Hello,world! 1766975546077

Process finished with exit code 0

相关:

https://blog.csdn.net/zhangphil/article/details/156145386

相关推荐
小书房3 小时前
Kotlin的by
android·开发语言·kotlin·委托·by
jinanwuhuaguo4 小时前
(第二十八篇)OpenClaw成本与感知的奇点——从“Token封建制”到“全民养虾”的本体论地基
android·人工智能·kotlin·拓扑学·openclaw
jinanwuhuaguo1 天前
OpenClaw联邦之心——从孤岛记忆到硅基集体潜意识的拓扑学革命(第二十三篇)
android·人工智能·kotlin·拓扑学·openclaw
pengyu1 天前
【Kotlin 协程修仙录 · 筑基境 · 后阶】 | 调度器的艺术:Dispatchers 四大护法与 withContext 性能密码
android·kotlin
千码君20161 天前
flutter: 分享一下基于trae cn 构建的过程
java·vscode·flutter·kotlin·trae
小书房2 天前
Kotlin的内联函数
java·开发语言·kotlin·inline·内联函数
zhangphil2 天前
Android Page3与Flow分页查媒体数据库展示宫格图片列表,Kotlin
android·kotlin
胡致和3 天前
配置变更后,弹窗为什么飞到了最左边?
kotlin
zhangphil3 天前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
小书房3 天前
Kotlin使用体验及理解1
android·开发语言·kotlin