Utiliser les Coroutines Kotlin pour gérer le threading
La raison pour laquelle le code plante est parce que le Bitmap
est en train d'être créé sur le Main Thread
, ce qui n'est pas autorisé car cela pourrait entraîner des erreurs de type Android Not Responding (ANR).
Concepts utilisés
- Les Coroutines Kotlin notes.
- Le pattern Chargement, Contenu, Erreur (LCE) est utilisé ci-dessous. Si vous êtes intéressé, vous pouvez en apprendre davantage à ce sujet dans cette conférence et cette vidéo.
- LiveData est utilisé pour retourner les données. J'ai compilé mes ressources LiveData préférées dans ces notes.
- Dans le code bonus,
toBitmap()
est une fonction d'extension Kotlin nécessitant d'ajouter cette bibliothèque aux dépendances de l'application.
Implémentation
Code
1. Créer un Bitmap
dans un thread différent du Main Thread
.
Dans cet exemple utilisant les Coroutines Kotlin, la fonction est exécutée dans le thread Dispatchers.IO
qui est destiné aux opérations basées sur le CPU. La fonction est préfixée par suspend
, qui est une syntaxe des Coroutines.
Bonus - Après la création du Bitmap
, il est également compressé dans un ByteArray
pour pouvoir être transmis via un Intent
plus tard décrit dans cet exemple complet.
Repository.kt
suspend fun bitmapToByteArray(url: String) = withContext(Dispatchers.IO) {
MutableLiveData>().apply {
postValue(Lce.Loading())
postValue(Lce.Content(ContentResult.ContentBitmap(
ByteArrayOutputStream().apply {
try {
BitmapFactory.decodeStream(URL(url).openConnection().apply {
doInput = true
connect()
}.getInputStream())
} catch (e: IOException) {
postValue(Lce.Error(ContentResult.ContentBitmap(ByteArray(0), "bitmapToByteArray error or null - ${e.localizedMessage}")))
null
}?.compress(CompressFormat.JPEG, BITMAP_COMPRESSION_QUALITY, this)
}.toByteArray(), "")))
}
}
ViewModel.kt
//Appelle bitmapToByteArray du Repository
private fun bitmapToByteArray(url: String) = liveData {
emitSource(switchMap(repository.bitmapToByteArray(url)) { lce ->
when (lce) {
is Lce.Loading -> liveData {}
is Lce.Content -> liveData {
emit(Event(ContentResult.ContentBitmap(lce.packet.image, lce.packet.errorMessage)))
}
is Lce.Error -> liveData {
Crashlytics.log(Log.WARN, LOG_TAG,
"bitmapToByteArray error or null - ${lce.packet.errorMessage}")
}
}
})
}
Bonus - Convertir un ByteArray
en Bitmap
.
Utils.kt
fun ByteArray.byteArrayToBitmap(context: Context) =
run {
BitmapFactory.decodeByteArray(this, BITMAP_OFFSET, size).run {
if (this != null) this
// Au cas où le Bitmap chargé serait vide ou s'il y a une erreur, j'ai un Bitmap par défaut à retourner.
else AppCompatResources.getDrawable(context, ic_coinverse_48dp)?.toBitmap()
}
}
1 votes
Quel message de crash obtenez-vous? Quelle est la trace de la pile? Savez-vous quelle ligne provoque le crash?
0 votes
La méthode createScalesBitmap lance une NullPointerException car bit est nul.
1 votes
Nécessaire l'autorisation Internet... Ajouté à androidmanifest.xml