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?
- ¿Cómo se puede convertir archivos de Java a archivos de Kotlin?
- ¿Cómo hacer referencia a otras opiniones en Anko DSL?
- ObjectAnimator.ofFloat no puede tomar Int como parámetros directamente en kotlin
- ¿Cómo mejorar la sintaxis kotlin lambda?
- Convertir el proyecto de Android para utilizar Gradle Script Kotlin
¿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()} } }
- ¿Cómo puedo representar una relación de muchos a muchos con Android Room?
- Kotlin android proguard error
- No se puede usar el valor argb color int en Kotlin?
- Jackson no puede cargar tipos JDK7 en Android
- ¿Cuál es la mejor manera de definir TAG constante en Kotlin?
- Advertencia de tiempo de ejecución de Kotlin desactualizada (plugin Kotlin 1.1.2-release-Studio2.3-3)
- ¿Debo cancelar la suscripción al utilizar rxbinding?
- Kotlin - Agregar artículos a ExpandableListView
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
- ¿Puede el nuevo constructor File () devolver null en Android?
- Cómo manejar los botones "guardar" y "cancelar" y la tecla de retroceso