Prefacio
Kotlin Coroutines es una nueva API asíncrona lanzada por Kotlin. No es la mejor solución a todos los problemas, pero con suerte, en muchos casos, hará las cosas un poco más fáciles. Aquí simplemente mostraré el plan de uso específico de esta biblioteca en Android. No diré mucho a continuación, echemos un vistazo a la introducción detallada juntos.
Introducción de coroutinas
// Agregue el siguiente código en el nodo Android en el archivo build.gradle de la aplicación kotlin {experimental {roroutines 'enable'}} // Agregue las siguientes dos líneas a la implementación de dependencia "org.jetbrains.kotlinx: kotlinx-coroutines-core: 0.20" implementación "org.jetbrains.kotlinx: kotlinx: kotlinx-coroutines-coroutines: 0.20".El primer ejemplo de Coroutinas
Por lo general, cargamos una imagen en ImageView, y la tarea de carga asincrónica es la siguiente:
Fun LoadBitMapFromMediaStore (ImageId: int, ImageBaseuri: Uri): bitmap {val uri = uri.withappendedPath (ImageBaseuri, imageId.ToString ()) return MediaStore.images.media.getBitMap (ContentResolver, Uri)}Este método debe ejecutarse en el hilo de fondo porque pertenece a una operación IO, lo que significa que tenemos muchas soluciones para iniciar la tarea de fondo, y una vez que el método devuelve un mapa de bits, necesitamos mostrarlo en la vista de imagen de inmediato.
ImageView.SetImageBitMap (Bitmap)
Esta línea de código debe ejecutarse en el hilo principal, de lo contrario se bloqueará.
Si las tres líneas de código anteriores se escriben juntas, el programa se atascará o se bloqueará, lo que depende de la selección razonable de hilos. A continuación, echemos un vistazo a cómo las coroutinas que usan Kotlin resuelven este problema:
val trabajo = lanzamiento (en segundo plano) {val uri = uri.withappendedPath (ImagesBaseuri, imageId.ToString ()) val bitmap = mediasStore.images.media.getBitMap (ContentResolver, Lunch (UI) {ImageView.SetImageBitMap (BitMap)}}Lo más importante aquí es el fondo de lanzamiento () y los parámetros y la interfaz de usuario. El lanzamiento () significa crear e iniciar una coroutine. El parámetro de fondo CoroutineContext se utiliza para garantizar la ejecución en el subproceso de fondo, para garantizar que la aplicación no se atasque o se bloquee. Puede declarar un CoroutineContext como se muestra a continuación.
Antual Val Background = newFixedThreadPoolContext (2, "BG")
Esto crea un nuevo contexto y usa dos hilos regulares al ejecutar sus tareas.
A continuación, el lanzamiento (UI), que activará otra coroutina, que se ejecutará en Android
hilo principal.
Cancelable
El próximo desafío es lidiar con cosas relacionadas con el ciclo de declaración de actividad. Cuando carga una tarea y deja la actividad antes de que haya terminado de ejecutarse, causará bloqueo al llamar imageView.setImageBitmap(bitmap) , por lo que debemos cancelar la tarea antes de abandonar la actividad. Aquí usamos el valor de retorno del método Launch (). Cuando la actividad llama al método ONStop, debemos usar el trabajo para cancelar la tarea.
Job.Cancel ()
Es como llamar a la eliminación cuando usa rxjava y llama a la función de cancelar cuando usa AsyncTask.
Ciclo de vida
Android Architecture Components proporciona a los desarrolladores de Android muchas bibliotecas potentes, una de las cuales es la API del ciclo de vida. Nos proporciona una manera fácil de escuchar el ciclo de vida de las actividades y fragmentos en tiempo real. Definamos el código para usar con las coroutinas.
class CoroutineLifecycleListener(val deferred: Deferred<*>) : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun cancelCoroutine() { if (!deferred.isCancelled) { deferred.cancel() } }}Creamos una función de extensión de ciclo de vida:
fun <T> LifecycleOwner.load(loader: () -> T): Deferred<T> { val deferred = async(context = Background, start = CoroutineStart.LAZY) { loader() } lifecycle.addObserver(CoroutineLifecycleListener(deferred)) return deferred} Hay demasiadas cosas nuevas en este método, y las explicaré una por una:
Ahora podemos llamar load() en una actividad o fragmento y acceder a los miembros del ciclo de vida desde esa función y agregar nuestro CoroutinElifecyClelistener como observador.
El método de carga requiere un cargador como parámetro, devolviendo un tipo general T. En el método de carga, llamamos a otra función de Coroutine Creator Async (), que utilizará el contexto de Coroutine de fondo para ejecutar tareas en el subproceso de fondo. Tenga en cuenta que este método tiene otro parámetro Start = CoroutInStart.Lazy, lo que significa que la coroutina no se ejecutará de inmediato, hasta que se llame.
Coroutine luego devolverá un objeto Defered<T> a la persona que llama, que es similar a nuestro trabajo anterior, pero también puede tener un valor de retraso, como JavaScript Promise o Future <T> en una API Java regular, e incluso mejor, tiene un método de espera.
A continuación, definimos otra función de extensión then() , esta vez la definimos por encima de Deferen<T> , que es el tipo devuelto por nuestro método de carga anterior. También toma un Lambda como parámetro, llamado bloque, que toma un solo objeto de tipo T como su parámetro.
Infix Fun <T> Diferido <T> .Then (Block: (t) -> Unidad): Job {return Launch (context = ui) {block ([email protected] ())}} Esta función creará otra coroutine utilizando launch() , que se ejecutará en el hilo principal esta vez. El Lambda (llamado bloque) pasó a esta coroutina toma el valor del objeto diferido completado como su parámetro. Llamamos await() para suspender la ejecución de esta coroutina hasta que el objeto diferido devuelva un valor.
Aquí es donde Coroutine se vuelve tan impresionante. La llamada a await() se realiza en el hilo principal, pero no bloquea una mayor ejecución de ese hilo. Simplemente pausará la ejecución de la función hasta que esté lista, cuando se reanude y pase el valor retrasado a la lambda. Cuando se suspende la coroutina, el hilo principal puede continuar realizando otras cosas. La función de espera es un concepto central en Coroutine, lo que crea todo tan mágico.
El observador de ciclo de vida agregado en load() cancelará la primera coroutina después de llamar onDestroy() en nuestra actividad. Esto también hará que se cancele la segunda coroutina, evitando que se llame block() .
Kotlin Coroutine DSL
Ahora que tenemos dos funciones de extensión y una clase que maneja la cancelación de Coroutine, veamos cómo usarla:
Load {LoadBitMapFromMediaStore (ImageID, ImageBaseuri)} Entonces {imageView.setImageBitMap (IT)} En el código anterior, pasamos el método Lambda a la función de carga, que llama al método LoadBitMapFromMediaStore, que debe ejecutarse en el subproceso de fondo hasta que el método devuelva un mapa de bits, y el valor de retorno del método de carga se Deferred<Bitmap> .
Como función de extensión, then() utiliza la declaración Infix. Aunque el método de carga devuelve Deferred<Bitmap> , se pasará al método entonces un valor de retorno de mapa de bits, por lo que podemos llamar directamente imageView.setImageBitmap(it) en el método entonces.
El código anterior se puede usar para cualquier llamada asincrónica que deba ocurrir en el hilo de fondo, y donde el valor de retorno debe devolverse al hilo principal, como en el ejemplo anterior. No hace múltiples llamadas como lo hace Rxjava, pero es más fácil de leer y puede cubrir muchos de los casos más comunes. Ahora puede hacer algo como esto de manera segura sin preocuparse por causar fugas de contexto o procesar hilos en cada llamada;
Load {Restapi.fetchData (Query)} entonces {adapter.display (it)}Luego, los métodos () y Load () son solo la punta del iceberg de esta nueva biblioteca, pero espero que algo similar aparezca en las futuras bibliotecas de Android con sede en Kotlin una vez que la versión Coroutine alcanza una versión estable. Antes de esto, puede usar o modificar el código anterior, o consulte ANKO Coroutines. También lanzé una versión más completa en GitHub. (https://github.com/erikhellman/kotlinasyncwithcoroutines (descarga local)).
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.