英文:
How to make Kotlin's LifecycleScope has sequential behaviour as Java's Executors.newSingleThreadExecutor?
问题
In Java Android, 为了在不阻塞主线程的情况下实现顺序行为,我正在使用以下代码。
Java Android
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> task0());
executor.execute(() -> task1());
executor.execute(() -> task2());
上述代码将始终按照task0,task1和task2函数的确切顺序执行,不管函数内部发生了什么。
我对Kotlin的LifecycleScope提供的生命周期感知功能印象深刻。我尝试以以下Kotlin的LifecycleScope形式编写代码。
Kotlin Android
val dispatcherForCalendar = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
lifecycleScope.launch(dispatcherForCalendar) {
    task0()
}
lifecycleScope.launch(dispatcherForCalendar) {
    task1()
}
lifecycleScope.launch(dispatcherForCalendar) {
    task2()
}
上述代码将按照task0,task1和task2函数的确切顺序执行,除非在函数中执行了延迟操作。
- 实际上,我不会在任务函数中显式插入
delay代码。在这种情况下,Android系统是否仍然可以隐式执行delay操作? - 如何实现与我的Java代码
Executors.newSingleThreadExecutor相同的顺序行为? 
谢谢。
英文:
In Java Android, to achieve sequential behavior without blocking main thread, this is the code I am using.
Java Android
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> task0());
executor.execute(() -> task1());
executor.execute(() -> task2());
The above code, will always execute in the exact order of task0, task1 and task2 functions regardless what is happening inside the functions.
I am impressed by the life cycle aware feature, offered by Kotlin's LifecycleScope. I try to write the code in the following Kotlin's LifecycleScope form.
Kotlin Android
val dispatcherForCalendar = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
lifecycleScope.launch(dispatcherForCalendar) {
    task0()
}
lifecycleScope.launch(dispatcherForCalendar) {
    task1()
}
lifecycleScope.launch(dispatcherForCalendar) {
    task2()
}
The above code will executed in the exact order of task0, task1 and task2 functions, except when delay is performed in the functions.
- In reality, I will not insert 
delaycode explicitly in task functions. In such a case, can Android system still performdelayoperation implicitly? - How I can achieve sequential behavior, same as my Java code 
Executors.newSingleThreadExecutor? 
Thank you.
答案1
得分: 1
Regarding 1):
协程可以在任何suspend函数调用时将线程返回给调度程序,而不仅仅是在delay()调用时。
Regarding 2):
我的答案在这里展示了如何使用通道(Channel)构建一个顺序任务队列。您可以在构造函数中注入一个CoroutineScope,以便在Activity或Fragment中使用时可以传递lifecycleScope。类似这样:
class JobQueue(
    private val scope: CoroutineScope,
    private val defaultContext: CoroutineContext = Dispatchers.Main
) {
    private val queue = Channel<Job>(Channel.UNLIMITED)
    init {
        scope.launch(Dispatchers.Default) {
            for (job in queue) job.join()
        }
    }
    fun submit(
        context: CoroutineContext = defaultContext,
        block: suspend CoroutineScope.() -> Unit
    ) {
        synchronized {
            val job = scope.launch(context, CoroutineStart.LAZY, block)
            queue.trySend(job)
        }
    }
}
如果这些是阻塞的任务,您可以例如将Dispatchers.IO作为运行任务的defaultContext。
英文:
Regarding 1):
The coroutines may yield the thread back to the dispatcher at any suspend function call, not just at delay() calls.
Regarding 2):
My answer here shows how you can build a sequential task queue using a Channel. You could modify the class to allow a CoroutineScope to be injected in the constructor, so lifecycleScope could be passed in when using it in an Activity or Fragment. Something like this:
class JobQueue(
    private val scope: CoroutineScope,
    private val defaultContext: CoroutineContext = Dispatchers.Main
) {
    private val queue = Channel<Job>(Channel.UNLIMITED)
    init { 
        scope.launch(Dispatchers.Default) {
            for (job in queue) job.join()
        }
    }
    fun submit(
        context: CoroutineContext = defaultContext,
        block: suspend CoroutineScope.() -> Unit
    ) {
        synchronized { 
            val job = scope.launch(context, CoroutineStart.LAZY, block)
            queue.trySend(job)
        }
    }
}
If these were blocking jobs, you might for example pass Dispatchers.IO as the defaultContext for running the jobs.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论