Préface
Kotlin Coroutines est une nouvelle API asynchrone lancée par Kotlin. Pas la meilleure solution à tous les problèmes, mais j'espère que dans de nombreux cas, cela facilitera un peu les choses. Ici, je vais simplement montrer le plan d'utilisation spécifique de cette bibliothèque dans Android. Je ne dirai pas beaucoup ci-dessous, jetons un coup d'œil à l'introduction détaillée ensemble.
Présentation des coroutines
// Ajoutez le code suivant dans le nœud Android dans le fichier build.gradle de l'application Kotlin {Experimental {Coroutines 'activy'}} // Ajoutez les deux lignes suivantes à l'implémentation de dépendance "org.jetbrains.kotlinx: kotlinx-corvetines-core: 0.20" implémentation "org.jetbrains.kotlinx: kotlinx-corossLe premier exemple de coroutines
Habituellement, nous chargeons une image dans ImageView, et la tâche de chargement asynchrone est la suivante:
Fun LoadBitMapFrommEdiAtore (ImageId: int, imagesbaseuri: uri): bitmap {val uri = uri.withappendPath (imagesbaseuri, imageid.toString ()) return mediater.images.media.getbitmap (contentResolver, uri)}Cette méthode doit être exécutée dans le thread d'arrière-plan car elle appartient à une opération IO, ce qui signifie que nous avons de nombreuses solutions pour démarrer la tâche d'arrière-plan, et une fois que la méthode renvoie un bitmap, nous devons l'afficher immédiatement dans ImageView.
ImageView.SetImageBitmap (Bitmap)
Cette ligne de code doit être exécutée dans le thread principal, sinon elle se bloquera.
Si les trois lignes de code ci-dessus sont écrites ensemble, le programme sera bloqué ou écrasé, ce qui dépend de la sélection raisonnable de threads. Ensuite, jetons un coup d'œil à la façon dont les coroutines utilisant Kotlin résout ce problème:
Val Job = Launch (background) {val uri = uri.withappendPath (imagesbaseuri, imageid.toString ()) val bitmap = mediaStore.images.media.getBitmap (contenuSolver, lancement (ui) {imageView.SetImageBitmap (bitmap)}}La chose la plus importante ici est le lancement () et le fond des paramètres et l'interface utilisateur. Lancement () signifie créer et démarrer une coroutine. Le paramètre d'arrière-plan CoroutineContext est utilisé pour assurer l'exécution dans le thread d'arrière-plan, afin de s'assurer que l'application ne sera pas bloquée ou écrasée. Vous pouvez déclarer un CoroutineContext comme indiqué ci-dessous.
Background de val interne = newFixEdThreadPoolContext (2, "bg")
Cela crée un nouveau contexte et utilise deux fils réguliers lors de l'exécution de ses tâches.
Ensuite, Launch (UI), qui déclenchera une autre coroutine, qui sera exécutée sur Android
Fil principal.
Non réduit
Le prochain défi consiste à traiter les choses liées au cycle de la déclaration d'activité. Lorsque vous chargez une tâche et quittez l'activité avant sa fin d'exécution, cela provoquera un crash lors de l'appel imageView.setImageBitmap(bitmap) , nous devons donc annuler la tâche avant de quitter l'activité. Ici, nous utilisons la valeur de retour de la méthode Launch (). Lorsque l'activité appelle la méthode onstop, nous devons utiliser le travail pour annuler la tâche.
job.cancel ()
C'est comme appeler Disser lorsque vous utilisez Rxjava et appelez la fonction Annuler lorsque vous utilisez AsyncTask.
LifecycleObserver
Android Architecture Components fournit aux développeurs Android de nombreuses bibliothèques puissantes, dont l'API de cycle de vie. Il nous offre un moyen facile d'écouter le cycle de vie des activités et des fragments en temps réel. Définissons le code à utiliser avec les coroutines.
Classe CoroutineLIFecycleListener (Val Deferser: Deferred <*>): LifecycleObserver {@onlifecycleEvent (lifecycycle.event.on_destroy) Fun CancelCoroutine () {if (! Deferred.iscancelled) {Deferred.Cancel ()}}}Nous créons une fonction d'extension de propriétaire de cycle de vie:
Fun <T> LifeccycleOner.Load (Loader: () -> T): différé <T> {val Deferred = Async (context = background, start = Coroutinestart.lazy) {Loder ()} Lifecycycle.Addobserver (CoroutineLIFecycleListener (DeFerred)) Retour différé} Il y a trop de nouvelles choses dans cette méthode, et je les expliquerai un par un:
Maintenant, nous pouvons appeler load() dans une activité ou un fragment et accéder aux membres du cycle de vie à partir de cette fonction et ajouter notre CoroutineliFecycleListener en tant qu'observateur.
La méthode de charge nécessite un chargeur en tant que paramètre, renvoyant un type général T. Dans la méthode de chargement, nous appelons une autre fonction Coroutine Creator Async (), qui utilisera le contexte Coroutine d'arrière-plan pour exécuter des tâches dans le thread d'arrière-plan. Notez que cette méthode a un autre paramètre start = CoroutineStart.lazy, ce qui signifie que la coroutine ne sera pas exécutée immédiatement, jusqu'à ce qu'elle soit appelée.
Coroutine renverra ensuite un objet Defered<T> à l'appelant, ce qui est similaire à notre travail précédent, mais il peut également porter une valeur de retard, tels que JavaScript Promise ou Future <T> dans une API Java ordinaire, et encore mieux, il a une méthode d'attente.
Ensuite, nous définissons une autre fonction d'extension then() , cette fois, nous la définissons au-dessus de Deferen<T> , qui est le type renvoyé par notre méthode de charge ci-dessus. Il prend également un lambda en tant que paramètre, nommé Block, qui prend un seul objet de type T comme paramètre.
infix fun <t> différé <T> .Then (bloc: (t) -> unité): Job {return lance (context = ui) {block ([email protected] ())}} Cette fonction créera une autre Coroutine à l'aide de launch() , qui s'exécutera cette fois sur le thread principal. Le Lambda (bloc nommé) transmis à cette coroutine prend la valeur de l'objet différé terminé comme paramètre. Nous appelons await() pour suspendre l'exécution de cette coroutine jusqu'à ce que l'objet différé renvoie une valeur.
C'est là que la coroutine devient si impressionnante. L'appel à await() est effectué sur le thread principal, mais ne bloque pas davantage l'exécution de ce thread. Il suscitera simplement l'exécution de la fonction jusqu'à ce qu'elle soit prête, lorsqu'elle reprendra et passe la valeur retardée à la Lambda. Lorsque la coroutine est suspendue, le fil principal peut continuer à effectuer d'autres choses. La fonction Await est un concept de base de la coroutine, ce qui crée le tout si magique.
L'observateur de cycle de vie ajouté dans load() annulera la première coroutine après avoir appelé onDestroy() sur notre activité. Cela entraînera également l'annulation de la deuxième coroutine, empêchant l'appel block() .
Kotlin Coroutine DSL
Maintenant que nous avons deux fonctions d'extension et une classe qui gère l'annulation de la coroutine, voyons comment l'utiliser:
Load {LoadBitMapFrommEdiAtore (imageId, imagesbaseuri)} puis {imageView.SetImageBitmap (it)} Dans le code ci-dessus, nous passons la méthode Lambda à la fonction de chargement, qui appelle la méthode LoadBitmapFrommEdiAtore, qui doit être exécutée sur le thread d'arrière-plan jusqu'à ce que la méthode renvoie un bitmap et la valeur de retour de la méthode de chargement soit Deferred<Bitmap> .
En tant que fonction d'extension, then() utilise la déclaration de l'infixe. Bien que la méthode de chargement renvoie Deferred<Bitmap> , il sera transmis à la méthode alors une valeur de retour bitmap, afin que nous puissions appeler directement imageView.setImageBitmap(it) dans la méthode alors.
Le code ci-dessus peut être utilisé pour tous les appels asynchrones qui doivent se produire sur le thread d'arrière-plan, et où la valeur de retour doit être renvoyée au thread principal, comme dans l'exemple ci-dessus. Il ne passe pas plusieurs appels comme le fait Rxjava, mais il est plus facile à lire et peut couvrir beaucoup des cas les plus courants. Maintenant, vous pouvez faire quelque chose comme celui-ci en toute sécurité sans vous soucier de provoquer des fuites de contexte ou du traitement des fils dans chaque appel;
charger {restapi.fetchData (query)} puis {adapter.display (it)}Ensuite () et les méthodes de charge () ne sont que la pointe de l'iceberg de cette nouvelle bibliothèque, mais j'espère que quelque chose de similaire apparaît dans les futures bibliothèques Android basées sur Kotlin une fois que la version Coroutine aura atteint une version stable. Avant cela, vous pouvez utiliser ou modifier le code ci-dessus, ou consulter Anko Coroutines. J'ai également publié une version plus complète sur GitHub. (https://github.com/erikhellman/kotlinasyncwithcoroutines (téléchargement local)).
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.