Home > Back-end >  How to load bitmap to Glance composable via Coil Uri?
How to load bitmap to Glance composable via Coil Uri?

Time:11-27

I am following the sample code from ImageGlanceWidget to load a bitmap to Glance via Uri.

As mentioned in the comments from this answer I have replaced getImageProvider() method with below code. However, when I do this I get error: Error in Glance App Widget java.io.FileNotFoundException: No content provider:/data/user/0/com.example.myappname/cache/image_cache/56448.....8e0ad2fac0.1.

How can I pull the bitmap from the coil disk cache?

private fun getImageProvider(context: Context, coilPath: String): ImageProvider {
    val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, coilPath.toUri())
    return ImageProvider(bitmap)
}

Parameter Values

val coilPath = context.imageLoader.diskCache?.get("https://picsum.photos/${width.roundToInt()}/${height.roundToInt()}")?.data?.toFile()?.path!! /*uses worker context*/
val context = LocalContext.current /*pass in context from glance composable to getImageProvider*/

Full Stack Trace

E/GlanceAppWidget: Error in Glance App Widget
    java.io.FileNotFoundException: No content provider: /data/user/0/com.example.mpappname/cache/image_cache/56448c7214ea904b18f01d34bdd997afd53c1c976abda4a67546d08e0ad2fac0.1
        at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:2013)
        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1842)
        at android.content.ContentResolver.openInputStream(ContentResolver.java:1518)
        at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:2322)
        at com.example.stockwidgetv1.clean.widget.glance.utility.WidgetDummy.getImageProvider2(WidgetDummy.kt:145)
        at com.example.stockwidgetv1.clean.widget.glance.utility.WidgetDummy.access$getImageProvider2(WidgetDummy.kt:44)
        at com.example.stockwidgetv1.clean.widget.glance.utility.WidgetDummy$Content$1.invoke(WidgetDummy.kt:101)
        at com.example.stockwidgetv1.clean.widget.glance.utility.WidgetDummy$Content$1.invoke(WidgetDummy.kt:97)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.glance.layout.BoxKt.Box(Box.kt:74)
        at com.example.stockwidgetv1.clean.widget.glance.utility.WidgetDummy.Content(WidgetDummy.kt:92)
        at androidx.glance.appwidget.GlanceAppWidget$setContent$1$1.invoke(GlanceAppWidget.kt:404)
        at androidx.glance.appwidget.GlanceAppWidget$setContent$1$1.invoke(GlanceAppWidget.kt:404)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.glance.appwidget.GlanceAppWidget$setContent$1.invoke(GlanceAppWidget.kt:398)
        at androidx.glance.appwidget.GlanceAppWidget$setContent$1.invoke(GlanceAppWidget.kt:397)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:78)
        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3248)
        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3238)
        at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
        at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1)
        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3238)
        at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3173)
        at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:587)
        at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:950)
        at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:519)
        at androidx.glance.appwidget.GlanceAppWidget.setContent-Cox8Y-g(GlanceAppWidget.kt:397)
        at androidx.glance.appwidget.GlanceAppWidget.access$setContent-Cox8Y-g(GlanceAppWidget.kt:72)
        at androidx.glance.appwidget.GlanceAppWidget$composeForSize$2.invokeSuspend(GlanceAppWidget.kt:372)
        at androidx.glance.appwidget.GlanceAppWidget$composeForSize$2.invoke(Unknown Source:8)
        at androidx.glance.appwidget.GlanceAppWidget$composeForSize$2.invoke(Unknown Source:4)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:169)
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
        at androidx.glance.appwidget.GlanceAppWidget.composeForSize-AAqiGWc$glance_appwidget_release(GlanceAppWidget.kt:365)
        at androidx.glance.appwidget.GlanceAppWidget$Api31Impl$composeAllSizes$2$allViews$1$1.invokeSuspend(GlanceAppWidget.kt:431)
E/GlanceAppWidget:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

CodePudding user response:

Use BitmapFactory.decodeFile() to get a Bitmap from a File pointing to a bitmap image.

It would be cleaner to just ask Coil to load the image. That way, you won't be trying to mess with Coil's cache (which Coil might also be manipulating, such as clearing entries), and you can deal with the race condition of your image have been ejected from the cache before you try using it:

val request = ImageRequest.Builder(context)
    .data("https://www.example.com/image.jpg")
    .build()
val bitmap = imageLoader.execute(request).drawable.bitmap
  • Related