Corotinas de Kotlin de la manera correcta en Android

Estoy intentando actualizar una lista dentro del adaptador usando el async, puedo ver que hay demasiado boilerplate.

¿Es la manera correcta de usar Kotlin Coroutines?

¿Se puede optimizar 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 más simple y claro de espera asíncrona 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 dependencias de Gradle para las corutinas son: kotlin-stdlib-jre7 , kotlinx-coroutines-android .

Nota: Use job.await() lugar de job.join() porque await await() rechaza excepciones, pero join() no. Si utiliza join() , tendrá que comprobar job.isCompletedExceptionally después de que el trabajo se complete.

Para iniciar llamadas simultáneas de retrofit, 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<Deferred<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 contexto de la UI para aplicaciones de Android en lugar de CommonPool .

El contexto UI es proporcionado por el módulo kotlinx-coroutines-android .

Como dijo sdeff, si utiliza el contexto de la interfaz de usuario, el código dentro de esa corutina se ejecutará en el subproceso de la interfaz de usuario de forma predeterminada. Y, si necesita ejecutar una instrucción en otro subproceso, puede utilizar run(CommonPool) {}

Además, si no necesita devolver nada del método, puede utilizar la función de launch(UI) lugar de async(UI) (el primero devolverá un Job y el último un Deferred<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 necesitas más ayuda te recomiendo que leas la guía principal de kotlinx.coroutines y, además, la guía de coroutines + UI

  • El procesamiento de anotaciones de Kotlin ignora los elementos con nombres similares
  • Android: no se puede actualizar ListView con CustomAdapter
  • Ordenar la colección por varios campos en Kotlin
  • Kotlin - Error intermitente de "archivo de clase incorrecta"
  • Gradle 3.0.0-alpha1 no es compatible con kotlin-android plugin 1.1.2-3?
  • Retrofit2 y kotlin
  • Firebase y recuperando elementos
  • Android Parcelable en Kotlin
  • Problemas al intentar generar aplicaciones de Kotlin con Android Studio
  • ¿Cómo puedo ejecutar una única prueba de Android con Kotlin?
  • Deshabilitar la generación incremental para kapt
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.