1

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)
mars8
  • 770
  • 1
  • 11
  • 25

1 Answers1

1

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
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • thanks, in my use case I won't be making http requests for image. how would I get this to work with local file i.e. `.data(file)`? P.s. the second hyper link in your answer is same as the first... – mars8 Nov 26 '22 at 14:11
  • @mairs8: "in my use case I won't be making http requests for image" -- according to your question, you are loading an image from `picsum.photos`. Regardless, try passing a `File` object to `data()`. A `File` at least [works with `load()`](https://github.com/coil-kt/coil#imageviews). And sorry about the URL -- I forgot that GitHub doesn't copy the URL to the clipboard when you click the link icon the way that the Android docs do. It's fixed now. – CommonsWare Nov 26 '22 at 14:17
  • "Use BitmapFactory.decodeFile() to get a Bitmap from a File pointing to a bitmap image.". I can successfully see my bitmap saved in the file location in device file explorer. However when I use decodefile(file) I get error `E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: file:/data/user/0/com.example.myappname/files/glance/64/130_101.png: open failed: ENOENT (No such file or directory)`. Any ideas? – mars8 Nov 26 '22 at 16:33
  • the exact `file` path value is the following `file:///data/user/0/com.example.myappname/files/glance/64/130_101.png` – mars8 Nov 26 '22 at 16:34
  • 1
    @mairs8: You appear to be creating your `File` object incorrectly. The filesystem path should not have a `file:` prefix on it. – CommonsWare Nov 26 '22 at 16:36
  • thanks, I was using `uri.toString` instead of `uri.path` which was adding the `file:\\` prefix – mars8 Nov 26 '22 at 17:13