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

相关推荐
Enaium8 小时前
我实现了KMP的SDL绑定并编写了高性能软光追
前端·kotlin
Android打工仔9 小时前
Continuation 的链式关系 —— 一个 suspend 函数如何把结果交还给调用者?
android·kotlin
Kapaseker10 小时前
小白都看得懂的 Skill 教程 - 初识 Skill
android·kotlin·vibecoding
zhangphil11 小时前
Android Coil 3 ImageRequest.Builder error() 和 fallback()异同
android·kotlin
我命由我123451 天前
Android 控件 - CardView(快速实现圆角)
android·java·java-ee·kotlin·android studio·android-studio·android runtime
大黄说说1 天前
Java 与 Kotlin 混合开发避坑指南:老项目平滑迁移 Kotlin 实操手册
java·开发语言·kotlin
我命由我123451 天前
Android Drawable - gradient
android·java·java-ee·kotlin·android studio·android-studio·android runtime
Kapaseker1 天前
AI 时代,读源码还有用吗?从 Kotlin 集合排序说起
android·kotlin
YB13752 天前
jetpack compose 副作用 SideEffect
android·kotlin
唐青枫2 天前
Kotlin interface 详解:别再把接口写成空壳和万能开关
kotlin