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

相关推荐
limuyang232 分钟前
PDF Viewer KMP(基于 chrome 的 PDFium 内核)
android·kotlin
pengyu8 小时前
【Kotlin 协程修仙录 · 大乘境 · 初阶】 | 跳出三界:协程在 KMP 与后端开发中的跨平台之道
android·kotlin
XiaoLeisj12 小时前
Jetpack Compose 知识点
android·kotlin·android jetpack·compose
Kapaseker17 小时前
Compose SelectionState API — 主动控制文本选择
android·kotlin
小强闯江湖1 天前
不只是让 AI 写代码:ViewCompose 把 Android UI 做成了可编译、可渲染的闭环
android·人工智能·kotlin
bytebitx2 天前
MacOS 编译腾讯 Mars XLog 及使用(已16KB对齐)
kotlin·mac·apk
alexhilton3 天前
让架构边界变成可执行的测试
android·kotlin·android jetpack
数据治理自习室3 天前
AI 应用评测体系(GraphRAG)
android·大数据·人工智能·kotlin
名剑走天下5 天前
Android 面试题大全
android·kotlin
chjif5 天前
Android 设备管控开发实战:自定义 Launcher 如何只显示指定 App?
android·kotlin