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

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

Android官方已经把AsyncTaskLoader标记为废弃,并建议开发者使用Kotlin最新的协程+flow实现AsyncTaskLoader的功能。现在用Kotlin原生的管道Channel与flow,结合协程,实现一种类似于AsyncTaskLoader的并发异步加载框架。数据更新到view或ui层,选择使用Kotlin的"可观察数据委托"架构Delegates.observable。

Kotlin 复制代码
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 mResultChannel = Channel<D?>()

    val mTaskChannel = Channel<Msg?>()
    val mThreadPool = newFixedThreadPoolContext(nThreads = 4, name = "my-thread")

    private var mTask: Job

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

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

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

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

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

    fun close() {
        mTaskChannel.close()
        mResultChannel.close()
        mTask.cancel()
    }

    class Msg {
        val timestamp = System.currentTimeMillis()
    }
}
Kotlin 复制代码
import kotlin.properties.Delegates
import kotlin.reflect.KProperty

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

    private var mChangeCallback: ChangeCallback<D>? = null

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

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

    fun onChange(callback: ChangeCallback<D>?) {
        mChangeCallback = callback
    }

    interface ChangeCallback<D> {
        fun dataChange(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(mLoader?.mThreadPool!!).async {
            mLoader?.mResultChannel?.receiveAsFlow()?.collect {
                mLiveData.value = it as D
            }
        }
    }

    open fun getLoader(): Loader<D>? {
        TODO()
    }
}
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
    }
}
Kotlin 复制代码
class MyDVM : DVModel<String, Loader<String>> {
    private val TAG = "MyDVM"

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

    override fun getLoader(): Loader<String>? {
        return MyLoader()
    }
}

测试的主类:

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


fun main() {
    val TAG = "main"

    runBlocking {
        val dvm = MyDVM()

        dvm.mLiveData.onChange(object : ChangeCallback<String> {
            override fun dataChange(old: String?, new: String?) {
                println("收到 $old $new")
            }
        })

        async(dvm.mLoader?.mThreadPool!!) {
            repeat(5) {
                println("--")
                println("$TAG startLoad $it ${Thread.currentThread().name}")

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

运行输出:

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

收到 null Hello,world! 1766471011855

--

main startLoad 1 my-thread-4

MyLoader loadInBackground ... my-thread-3

MyLoader loadInBackground done my-thread-3

收到 Hello,world! 1766471011855 Hello,world! 1766471014865

--

main startLoad 2 my-thread-4

MyLoader loadInBackground ... my-thread-4

MyLoader loadInBackground done my-thread-4

收到 Hello,world! 1766471014865 Hello,world! 1766471017872

--

main startLoad 3 my-thread-1

MyLoader loadInBackground ... my-thread-4

MyLoader loadInBackground done my-thread-4

收到 Hello,world! 1766471017872 Hello,world! 1766471020887

--

main startLoad 4 my-thread-4

MyLoader loadInBackground ... my-thread-3

MyLoader loadInBackground done my-thread-3

收到 Hello,world! 1766471020887 Hello,world! 1766471023901

Process finished with exit code 0

相关:

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

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

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

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

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

相关推荐
zh_xuan10 小时前
kotlin 类继承的语法2
开发语言·kotlin
stevenzqzq15 小时前
kotlin 协程的用法
kotlin
DCTANT16 小时前
【原创】使用更优雅的方式改造MyBatisPlus逻辑删除插件
spring boot·后端·mysql·kotlin·mybatis·mybatisplus
lynn8570_blog16 小时前
关于compose的remember
android·kotlin
冬奇Lab19 小时前
【Kotlin系列04】类与对象基础:从Java Bean到Data Class的优雅蜕变
android·kotlin·编程语言
撩得Android一次心动19 小时前
Android Lifecycle 全面解析:掌握生命周期管理的艺术(1)
android·java·kotlin·lifecycle
yeziyfx1 天前
kotlin中 ?:的用法
android·开发语言·kotlin
Kapaseker2 天前
千锤百炼写View 摸爬滚打名声就
android·kotlin