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

相关推荐
Yang-Never2 小时前
Android 内存泄漏 -> ViewModel持有Activity/Fragment导致的内存泄漏
android·java·开发语言·kotlin·android studio
Yang-Never3 小时前
Android 内存泄漏 -> LiveData如何解决ViewMode和Activity/Fragment之间的内存泄漏
android·java·开发语言·kotlin·android studio
HeDongDong-3 小时前
Kotlin 协程(Coroutines)详解
android·开发语言·kotlin
Kapaseker5 小时前
凌晨两点磨锋芒 调试采坑莫慌张
android·kotlin
F_D_Z20 小时前
岭回归(Ridge Regression)辨析
回归·kotlin·l2正则
6666v61 天前
Android Kotlin(3) Flow异步流
android·kotlin
QING6181 天前
Kotlin Flow 中 flatMap 与 flatMapLatest 的核心差异 —— 新手指南
android·kotlin·android jetpack
HeDongDong-1 天前
Kotlin Lambda 表达式详解
android·开发语言·kotlin
aqi002 天前
FFmpeg开发笔记(九十六)采用Kotlin+Compose的视频编辑器OpenVideoEditor
android·ffmpeg·kotlin·音视频·流媒体