Kotlin Coroutines el path correcto en Android

Estoy tratando de actualizar una list dentro del adaptador usando asynchronous, puedo ver que hay mucho text repetitivo.

¿Es la forma correcta de usar Koutlin Coroutines?

¿se puede optimizar esto más?

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()} } } 

Después de luchar con esta pregunta durante días, creo que el patrón async-await más simple y claro para las actividades de Android con Kotlin es:

 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. } } 

Las únicas dependencies de Gradle para corutinas son: kotlin-stdlib-jre7 , kotlinx-coroutines-android .

Nota: Use job.await() lugar de job.join() porque await await() vuelve a generar excepciones, pero join() no lo hace. Si usa join() , deberá verificar el job.isCompletedExceptionally después de que el trabajo finalice.

Para iniciar llamadas de actualización simultáneas , puede hacer esto:

 val jobA = async(CommonPool) { /* Blocking call A */ }; val jobB = async(CommonPool) { /* Blocking call B */ }; jobA.await(); jobB.await(); 

O:

 val jobs = arrayListOf<Defernetworking<Unit>>(); jobs += async(CommonPool) { /* Blocking call A */ }; jobs += async(CommonPool) { /* Blocking call B */ }; jobs.forEach { it.await(); }; 

Creo que puedes deshacerte de runOnUiThread { ... } usando el context de UI para aplicaciones de Android en lugar de CommonPool .

El context de la UI es proporcionado por el module kotlinx-coroutines-android .

También tenemos otra opción. si usamos la biblioteca Anko , entonces parece que esto

 doAsync { // Call all operation related to network or other ui blocking operations here. uiThread { // perform all ui related operation here } } 

Agregue dependencia para Anko en su app gradle de esta manera.

 compile "org.jetbrains.anko:anko:0.10.3" 

Como dijo sdeff, si usas el context de UI, el código dentro de esa corutina se ejecutará en el hilo de UI por defecto. Y, si necesita ejecutar una instrucción en otro hilo, puede usar run(CommonPool) {}

Además, si no necesita devolver nada del método, puede usar la function de launch(UI) lugar de async(UI) (la primera devolverá una Job y la última una Defernetworking<Unit> ).

Un ejemplo podría ser:

 fun loadListOfMediaInAsync() = launch(UI) { try { run(CommonPool) { //The coroutine is suspended until run() ends adapter.listOfMediaItems.addAll(resources.getAllTracks()) } adapter.notifyDataSetChanged() } catch(e: Exception) { e.printStackTrace() } catch(o: OutOfMemoryError) { o.printStackTrace() } finally { progress.dismiss() } } 

Si necesita más ayuda, le recomiendo que lea la guía principal de kotlinx.coroutines y, además, la guía de corutinas + UI