bumptech / glide

An image loading and caching library for Android focused on smooth scrolling
https://bumptech.github.io/glide/
Other
34.57k stars 6.12k forks source link

[AppWidgetTarget/RemoteViews] Crash NullPointerException on android.util.ArrayMap.get #4606

Open ampedNinja opened 3 years ago

ampedNinja commented 3 years ago

Crash when passing multiple RemoteViews for landscape/portrait to updateAppWidget.

https://github.com/ampedNinja/appwidget_demo

Glide Version: 4.9.0

Integration libraries: OkHttp3

Device/Android Version: Pixel 5 11.0 and Zenfone 8 11.0

Issue details / Repro steps / Use case background: I'm creating an appWidget for the home screen where I must pass separate RemoteViews objects for landscape and portrait mode. However when I implement this, there's a crash on Glide. The layout is a bit complicated, with different layouts being used depending on how much space is available, so on resizing the widget, I choose the best layout for landscape, and the best for portrait.

This crash doesn't happen if I remove setting the imageview bitmap with glide and pass updateAppWidget RemoteViews(RemoteViews landscape, RemoteViews portrait) or if I use glide but only pass a single RemoteViews to appWidgetManager.updateAppWidget

I've attached a simplified demo project.

AppWidget.kt:

fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
      appWidgetId: Int) {
    val profilePicUrl = "https://source.unsplash.com/random"

    // Construct the RemoteViews object
    val rvPortrait = RemoteViews(context.packageName, R.layout.app_widget)
    val rvLandscape = RemoteViews(context.packageName, R.layout.app_widget)
    rvPortrait.setTextViewText(R.id.appwidget_text, "portrait")
    rvLandscape.setTextViewText(R.id.appwidget_text, "landscape")

    // Construct AppWidgetTargets, not sure if separate ones are needed for orientation
    val awtPortrait = AppWidgetTarget(context, R.id.appwidget_imageview, rvPortrait, appWidgetId)
    val awtLandscape = AppWidgetTarget(context, R.id.appwidget_imageview, rvLandscape , appWidgetId)

    Glide.with(context) //Portrait
        .asBitmap()
        .load(profilePicUrl)
        .placeholder(R.drawable.ic_profile_placeholder)
        .error(R.drawable.ic_profile_placeholder)
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .transform(CircleCrop())
        .into(awtPortrait)

    Glide.with(context) // Landscape
        .asBitmap()
        .load(profilePicUrl)
        .placeholder(R.drawable.ic_profile_placeholder)
        .error(R.drawable.ic_profile_placeholder)
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .transform(CircleCrop())
        .into(awtLandscape)

    // Instruct the widget manager to update the widget
    appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(rvLandscape, rvPortrait))
  }

Layout XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/appWidgetBackgroundColor"
    android:padding="@dimen/widget_margin"
    android:theme="@style/ThemeOverlay.Wendergramfinal.AppWidgetContainer">

  <ImageView
      android:id="@+id/appwidget_imageview"
      android:layout_width="50dp"
      android:layout_height="50dp"
      android:background="#FFFFFF"/>

  <TextView
      android:id="@+id/appwidget_text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_centerVertical="true"
      android:layout_margin="8dp"
      android:background="?attr/appWidgetBackgroundColor"
      android:contentDescription="@string/appwidget_text"
      android:text="@string/appwidget_text"
      android:textColor="?attr/appWidgetTextColor"
      android:textSize="24sp"
      android:textStyle="bold|italic" />
</RelativeLayout>

Stack trace / LogCat:

2021-08-02 20:52:07.768 20317-20317/com.raywenderlich.android.wendergram E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.raywenderlich.android.wendergram, PID: 20317
    com.bumptech.glide.load.engine.CallbackException: Unexpected exception thrown by non-Glide code
        at com.bumptech.glide.load.engine.EngineJob.callCallbackOnResourceReady(EngineJob.java:154)
        at com.bumptech.glide.load.engine.EngineJob$CallResourceReady.run(EngineJob.java:398)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7664)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.ArrayMap.get(java.lang.Object)' on a null object reference
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2379)
        at android.os.Parcel.createException(Parcel.java:2357)
        at android.os.Parcel.readException(Parcel.java:2340)
        at android.os.Parcel.readException(Parcel.java:2282)
        at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetIds(IAppWidgetService.java:977)
        at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:531)
        at com.bumptech.glide.request.target.AppWidgetTarget.update(AppWidgetTarget.java:118)
        at com.bumptech.glide.request.target.AppWidgetTarget.onResourceReady(AppWidgetTarget.java:126)
        at com.bumptech.glide.request.target.AppWidgetTarget.onResourceReady(AppWidgetTarget.java:21)
        at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:582)
        at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:544)
        at com.bumptech.glide.load.engine.EngineJob.callCallbackOnResourceReady(EngineJob.java:152)
        at com.bumptech.glide.load.engine.EngineJob$CallResourceReady.run(EngineJob.java:398) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7664) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
     Caused by: android.os.RemoteException: Remote stack trace:
        at android.os.Parcel.readSquashed(Parcel.java:2082)
        at android.content.pm.ApplicationInfo$1.createFromParcel(ApplicationInfo.java:1776)
        at android.content.pm.ApplicationInfo$1.createFromParcel(ApplicationInfo.java:1773)
        at android.widget.RemoteViews.<init>(RemoteViews.java:2360)
        at android.widget.RemoteViews.<init>(RemoteViews.java:2334)
ampedNinja commented 2 years ago

Can work around issue by keeping a reference to the RemoteViews object, and overriding onResourceReady to call to update the widget via AppWidget.updateAppWidget(...) with a RemoteViews(rvLandscape, rvPortrait) object. If you try to provide a RemoteViews map to AppWidget.updateAppWidget(...)that doesn't match the original constructors composition, crash will occur.