Coil Kotlin Uri to Bitmap throws null pointer exception

Viewed 123

Trying to convert a Uri image file to Bitmap in Kotlin fails with a Null Pointer exception. How can I fix this?

var bitmap = remember {  mutableStateOf<Bitmap?>(null)}

LaunchedEffect(key1 = "tobitmap") {
    CoroutineScope(Dispatchers.IO).launch {
        bitmap.value = uriToBitmap(
            context,
            shoppingListScreenViewModel.state.value.imageUri
        )
    }
}

Image(
    bitmap = bitmap.value?.asImageBitmap()!!, //Throws exception here
    contentDescription = ""
)

private suspend fun uriToBitmap(context: Context, uri: Uri?): Bitmap {

    val loader = ImageLoader(context)
    val request = ImageRequest.Builder(context)
        .data(uri)
        .allowHardware(false) // Disable hardware bitmaps.
        .build()

    val result = (loader.execute(request) as SuccessResult).drawable
    val bitmap = (result as BitmapDrawable).bitmap

    val resizedBitmap = Bitmap.createScaledBitmap(
        bitmap, 80, 80, true);

    return resizedBitmap
}
2 Answers
var bitmap = remember {  mutableStateOf<Bitmap?>(null)}

Here, bitmap.value will be null.

Image(
    bitmap = bitmap.value?.asImageBitmap()!!, //Throws exception here
    contentDescription = ""
)

Here, bitmap.value?.asImageBitmap() will be null, since bitmap.value is null. As a result, you will crash with a NullPointerException as soon as you execute this code.

Eventually, bitmap.value will not be null, courtesy of your LaunchedEffect, but that will take some time. You need to rework your composable to be able to work prior to that point in time.

bitmap = bitmap.value?.asImageBitmap()!!, //Throws exception here

not-null assertion is not a good way to handle this.

Your possible options are either display Image with

bitmap?.value?.asImageBitmap()?.let{ imageBitmap->
   Image(...)
} 

and wait for bitmap to be created while you display nothing

or display preferably a Composable for loading or Image with placeholder.

if(bitmap.value!= null) {
  Image(...)
} else {
 // Your loading Composable
}

Another option is to use SubcomposeAsyncImage which has slots for Loading, Error and Success Composable slots so you can pass your Composables inside these slots.

Related