Sai*_*Sai 38 android coroutine async-await kotlin
我正在尝试使用异步更新适配器内的列表,我可以看到有太多的样板.
这是使用Kotlin Coroutines的正确方法吗?
这可以更优化吗?
fun loadListOfMediaInAsync() = async(CommonPool) {
try {
//Long running task
adapter.listOfMediaItems.addAll(resources.getAllTracks())
runOnUiThread {
adapter.notifyDataSetChanged()
progress.dismiss()
}
} catch (e: Exception) {
e.printStackTrace()
runOnUiThread {progress.dismiss()}
} catch (o: OutOfMemoryError) {
o.printStackTrace()
runOnUiThread {progress.dismiss()}
}
}
Run Code Online (Sandbox Code Playgroud)
KTC*_*TCO 38
经过几天的挣扎,我认为使用Kotlin的Android活动最简单明了的async-await模式是:
override fun onCreate(savedInstanceState: Bundle?) {
//...
loadDataAsync(); //"Fire-and-forget"
}
fun loadDataAsync() = async(UI) {
try {
//Turn on busy indicator.
val job = async(CommonPool) {
//We're on a background thread here.
//Execute blocking calls, such as retrofit call.execute().body() + caching.
}
job.await();
//We're back on the main thread here.
//Update UI controls such as RecyclerView adapter data.
}
catch (e: Exception) {
}
finally {
//Turn off busy indicator.
}
}
Run Code Online (Sandbox Code Playgroud)
协同程序的唯一Gradle依赖项是:kotlin-stdlib-jre7,kotlinx-coroutines-android.
注意:使用job.await()而不是job.join()因为await()重新抛出异常,但join()不是.如果您使用join(),则需要job.isCompletedExceptionally在作业完成后进行检查.
要启动并发改装调用,您可以执行以下操作:
val jobA = async(CommonPool) { /* Blocking call A */ };
val jobB = async(CommonPool) { /* Blocking call B */ };
jobA.await();
jobB.await();
Run Code Online (Sandbox Code Playgroud)
要么:
val jobs = arrayListOf<Deferred<Unit>>();
jobs += async(CommonPool) { /* Blocking call A */ };
jobs += async(CommonPool) { /* Blocking call B */ };
jobs.forEach { it.await(); };
Run Code Online (Sandbox Code Playgroud)
Dmy*_*lyk 33
如何启动协程
在kotlinx.coroutines库中,您可以使用launch或者async函数启动新的协同程序.
从概念上讲,async就像launch.它启动一个单独的协程,这是一个轻量级的线程,与所有其他协同程序同时工作.
不同之处在于,启动返回a Job并且不携带任何结果值,而async返回a Deferred- 轻量级非阻塞未来,表示稍后提供结果的承诺.您可以使用.await()延迟值来获取其最终结果,但Deferred也是a Job,因此您可以根据需要取消它.
协同上下文
在Android中我们通常使用两个上下文:
uiContext将执行分派到Android主UI线程(用于父协程).bgContext在后台线程中调度执行(对于子协同程序).例
//dispatches execution onto the Android main UI thread
private val uiContext: CoroutineContext = UI
//represents a common pool of shared threads as the coroutine dispatcher
private val bgContext: CoroutineContext = CommonPool
Run Code Online (Sandbox Code Playgroud)
在下面的例子中,我们将使用CommonPool用于bgContext这限制并行运行,它的值的线程数Runtime.getRuntime.availableProcessors()-1.因此,如果安排了协程任务,但所有核心都被占用,它将排队.
您可能需要考虑使用newFixedThreadPoolContext或自己实现的缓存线程池.
启动+异步(执行任务)
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
val task = async(bgContext) { dataProvider.loadData("Task") }
val result = task.await() // non ui thread, suspend until finished
view.showData(result) // ui thread
}
Run Code Online (Sandbox Code Playgroud)
launch + async + async(按顺序执行两个任务)
注意:task1和task2按顺序执行.
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
// non ui thread, suspend until task is finished
val result1 = async(bgContext) { dataProvider.loadData("Task 1") }.await()
// non ui thread, suspend until task is finished
val result2 = async(bgContext) { dataProvider.loadData("Task 2") }.await()
val result = "$result1 $result2" // ui thread
view.showData(result) // ui thread
}
Run Code Online (Sandbox Code Playgroud)
launch + async + async(并行执行两个任务)
注意:task1和task2是并行执行的.
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
val task1 = async(bgContext) { dataProvider.loadData("Task 1") }
val task2 = async(bgContext) { dataProvider.loadData("Task 2") }
val result = "${task1.await()} ${task2.await()}" // non ui thread, suspend until finished
view.showData(result) // ui thread
}
Run Code Online (Sandbox Code Playgroud)
如何取消协程
该函数loadData返回一个Job可能被取消的对象.当取消父协程时,它的所有子节点也会被递归取消.
如果stopPresenting函数被调用,同时dataProvider.loadData仍在进行中,该功能view.showData将永远不会被调用.
var job: Job? = null
fun startPresenting() {
job = loadData()
}
fun stopPresenting() {
job?.cancel()
}
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
val task = async(bgContext) { dataProvider.loadData("Task") }
val result = task.await() // non ui thread, suspend until finished
view.showData(result) // ui thread
}
Run Code Online (Sandbox Code Playgroud)
完整的答案可以在我的文章Android Coroutine Recipes中找到
小智 5
我们还有另一种选择.如果我们使用Anko库,那么它看起来像这样
doAsync {
// Call all operation related to network or other ui blocking operations here.
uiThread {
// perform all ui related operation here
}
}
Run Code Online (Sandbox Code Playgroud)
像这样在您的应用程序gradle中添加Anko的依赖项.
compile "org.jetbrains.anko:anko:0.10.3"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
27851 次 |
| 最近记录: |