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

相关推荐
ai2work3 天前
ch23 综合复刻:从零做一个最小可用版本(capstone)
kotlin
ai2work3 天前
ch21 签名、校验与发版
kotlin
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
Android打工仔3 天前
Kotlin 协程源码解析:协程是如何切换线程的?
android·kotlin
ai2work3 天前
附录 D 速查索引与阅读指南
kotlin
ai2work3 天前
ch22 诊断方法论:三个真实事故的根因分析
kotlin
Kapaseker3 天前
你有搞明白 Volatile 什么意思吗?
android·kotlin
alexhilton3 天前
藏在设备上的秘密,终究藏不住
android·kotlin·android jetpack
ai2work4 天前
ch15 加载模型与初始化上下文
kotlin
hai_android4 天前
Kotlin / Android 常用函数使用示例手册
android·java·kotlin