Search code examples
androidandroid-widgetandroid-jetpack-composeglance-appwidget

Crash in glance app widget image when trying to display bitmap


When I try to display a bitmap image (of my app icon) in the app, it works ok, but crashes when I try to display it in Widget Glance.

This is my code for bitmap:

    val icon = packageManager.getApplicationIcon("com.myapp.packagename")
    val bitmap: Bitmap = try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            getAppIconV26(applicationContext, "com.myapp.packagename")
        } else {
            (icon as BitmapDrawable).bitmap
        }
    } catch (e: Exception) {
        (ResourcesCompat.getDrawable(applicationContext.resources, R.drawable.placeholder, null) as BitmapDrawable).bitmap

And this is jetpack compose Image, which loads bitmap fine:

androidx.compose.foundation.Image(
    modifier = Modifier.size(46.dp), 
    bitmap = bitmap.asImageBitmap(),
    contentDescription = null),
}

but when I try to load the same bitmap in the widget using Jetpack Glance Image, the widget crashes:

androidx.glance.Image(
    modifier = GlanceModifier.size(46.dp),
    provider = ImageProvider(bitmap),
    contentDescription = null,
)

Crash:

E/GlanceAppWidget: Error in Glance App Widget
    java.lang.RuntimeException: Tried to marshall a Parcel that contained Binder objects.
        at android.os.Parcel.nativeMarshall(Native Method)
        at android.os.Parcel.marshall(Parcel.java:620)
        at androidx.core.widget.RemoteViewsCompatService$RemoteViewsCompatServiceData$Companion.serializeToBytes$core_remoteviews_release(RemoteViewsCompatService.kt:245)
        at androidx.core.widget.RemoteViewsCompatService$RemoteViewsCompatServiceData$Companion.create(RemoteViewsCompatService.kt:166)
        at androidx.core.widget.RemoteViewsCompatService$Companion.saveItems(RemoteViewsCompatService.kt:306)
        at androidx.core.widget.RemoteViewsCompat.setRemoteAdapter(RemoteViewsCompat.kt:86)
        at androidx.glance.appwidget.translators.LazyListTranslatorKt.translateEmittableLazyList(LazyListTranslator.kt:90)
        at androidx.glance.appwidget.translators.LazyListTranslatorKt.translateEmittableLazyColumn(LazyListTranslator.kt:45)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateChild(RemoteViewsTranslator.kt:143)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.setChildren(RemoteViewsTranslator.kt:335)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateEmittableColumn(RemoteViewsTranslator.kt:268)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateChild(RemoteViewsTranslator.kt:140)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateComposition(RemoteViewsTranslator.kt:96)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateComposition-mU3eQPI(RemoteViewsTranslator.kt:63)
        at androidx.glance.appwidget.GlanceAppWidget$composeForSize$2.invokeSuspend(GlanceAppWidget.kt:393)
        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:165)
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
        at androidx.glance.appwidget.GlanceAppWidget.composeForSize-AAqiGWc$glance_appwidget_release(GlanceAppWidget.kt:371)
        at androidx.glance.appwidget.GlanceAppWidget.compose$glance_appwidget_release(GlanceAppWidget.kt:218)
        at androidx.glance.appwidget.GlanceAppWidget.compose$glance_appwidget_release(GlanceAppWidget.kt:201)
        at androidx.glance.appwidget.GlanceAppWidget$compose$1.invokeSuspend(Unknown Source:19)
        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:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

I don't understand this crash. Can somebody please help me understand what's wrong?


Solution

  • Glance translates into actual RemoteViews. Those are then passed to the host process (i.e the launcher/homescreen). There is a limitation in the size of the object that can be passed between process.

    It seems you are using a LazyColumn (thus a ListView) that displays many Bitmaps. It could be that you hit that size limit.

    Couple of things to try:

    • Try displaying just one with the same code
      • Does it work?
      • Does it work if you pass another small Bitmap? Maybe the issue is with the bitmap size or type?
    • Alternatively try using URIs instead of bitmaps or limit the number of items to be displayed.