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

  • Spring Boot no inicia el registrador automáticamente cuando usa @Cacheable
  • ¿Pasar lambdas a Observable.subscribe en kotlin dará como resultado pérdidas de memory?
  • Kotlin: anula la propiedad genérica dentro del subtipo
  • Reemplazar SAM-constructor con lambda con tipo covariante
  • ¿Cómo manejar los errores de escritura en Apache Jena?
  • Cómo usar TypeToken + generics con Gson en Kotlin
  • "Las proyecciones no están permitidas para los arguments inmediatos de un supertipo" Kotlin Android Studio
  • No se puede establecer ViewModel en Kotlin
  • Android numberPicker pasando widget de Android como valor
  • Error de data binding en Android Spinner
  • viewGroup return null en el adaptador Recyclerview