Skip to content

Instantly share code, notes, and snippets.

@yccheok
Created November 19, 2025 17:13
Show Gist options
  • Select an option

  • Save yccheok/6e512aac945b7c98986ee8e3bcc27570 to your computer and use it in GitHub Desktop.

Select an option

Save yccheok/6e512aac945b7c98986ee8e3bcc27570 to your computer and use it in GitHub Desktop.
This is how our home widget image loading code looks like.
// Used by list view home widget.
private static boolean loadRowRemoteViews(Context context, AppWidgetManager appWidgetManager, RemoteViews remoteViews, int appWidgetId, int collageViewLinearLayoutResourceId, List<Attachment> attachments, final int startIndex, final int maxCountPerRow, int widgetMinWidth, int margin) {
final int[] imageViewResourceids = {R.id.image_view_0, R.id.image_view_1, R.id.image_view_2};
Assert(maxCountPerRow == imageViewResourceids.length);
final int attachmentsSize = attachments.size();
if (startIndex >= attachmentsSize) {
return false;
}
// Adjust image view height?
RemoteViews rowRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.collage_view_row);
int _ei = Math.min(startIndex+maxCountPerRow, attachmentsSize);
final int countInThisRow = _ei - startIndex;
// Only if more than 1 image views affect.
if (countInThisRow > 1) {
double bestHeight = Double.MAX_VALUE;
for (int i=startIndex; i<_ei; i++) {
final Attachment attachment = attachments.get(i);
final Pair<Integer, Integer> bestSize = getBestSizeForWidget(attachment);
final int attWidth = bestSize.first;
final int attHeight = bestSize.second;
double ratio = (double) attWidth / ((widgetMinWidth - countInThisRow * 2.0 * margin) / countInThisRow);
double height = attHeight / ratio;
bestHeight = Math.min(bestHeight, height);
}
for (int i=startIndex; i<_ei; i++) {
final int imageViewResourceIdsIndex = i - startIndex;
final int imageViewResourceId = imageViewResourceids[imageViewResourceIdsIndex];
rowRemoteViews.setInt(imageViewResourceId, "setMaxHeight", (int) bestHeight);
rowRemoteViews.setInt(imageViewResourceId, "setMinimumHeight", (int) bestHeight);
}
}
for (int i=startIndex, ei=startIndex+maxCountPerRow; i<ei; i++) {
final int imageViewResourceIdsIndex = i-startIndex;
final int imageViewResourceId = imageViewResourceids[imageViewResourceIdsIndex];
if (i >= attachmentsSize) {
rowRemoteViews.setViewVisibility(imageViewResourceId, View.GONE);
// Continue to hide next image views.
continue;
}
rowRemoteViews.setViewVisibility(imageViewResourceId, View.VISIBLE);
final Attachment attachment = attachments.get(i);
final Pair<Integer, Integer> bestSize = getBestSizeForWidget(attachment);
final int width = bestSize.first;
final int height = bestSize.second;
try {
Bitmap bitmap = Glide.with(context)
.asBitmap()
.load(attachment.getPath())
.submit(width, height)
.get();
rowRemoteViews.setImageViewBitmap(imageViewResourceId, bitmap);
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "", e);
}
}
remoteViews.addView(collageViewLinearLayoutResourceId, rowRemoteViews);
return true;
}
It breaks, if we were using new RemoteViews.RemoteCollectionItems. It works, if we were using old notifyAppWidgetViewDataChanged.
java.lang.IllegalArgumentException: RemoteViews for widget update exceeds maximum bitmap memory usage (used: 507370180, max: 26956800)
at android.os.Parcel.createExceptionOrNull(Parcel.java:3344)
at android.os.Parcel.createException(Parcel.java:3324)
at android.os.Parcel.readException(Parcel.java:3307)
at android.os.Parcel.readException(Parcel.java:3249)
at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetIds(IAppWidgetService.java:951)
at android.appwidget.AppWidgetManager.lambda$updateAppWidget$5(AppWidgetManager.java:711)
at android.appwidget.AppWidgetManager.$r8$lambda$Emo9F9Eo3H92TWufpOrPKUtYf-g(Unknown Source:0)
at android.appwidget.AppWidgetManager$$ExternalSyntheticLambda11.acceptOrThrow(D8$$SyntheticClass:0)
at android.appwidget.AppWidgetManager.tryAdapterConversion(AppWidgetManager.java:680)
at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:711)
at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:785)
at com.yocto.wenote.widget.NoteListAppWidgetProvider.safeUpdateAppWidget(NoteListAppWidgetProvider.java:601)
at com.yocto.wenote.widget.NoteListAppWidgetProvider.lambda$setRemoteAdapter$7(NoteListAppWidgetProvider.java:504)
at com.yocto.wenote.widget.NoteListAppWidgetProvider$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at com.yocto.wenote.ui.Utils$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at android.os.Handler.handleCallback(Handler.java:995)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loopOnce(Looper.java:248)
at android.os.Looper.loop(Looper.java:338)
at android.app.ActivityThread.main(ActivityThread.java:9067)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.appwidget.AppWidgetServiceImpl.updateAppWidgetInstanceLocked(AppWidgetServiceImpl.java:2896)
at com.android.server.appwidget.AppWidgetServiceImpl.updateAppWidgetIds(AppWidgetServiceImpl.java:2617)
at com.android.server.appwidget.AppWidgetServiceImpl.updateAppWidgetIds(AppWidgetServiceImpl.java:2141)
at com.android.internal.appwidget.IAppWidgetService$Stub.onTransact(IAppWidgetService.java:457)
at android.os.Binder.execTransactInternal(Binder.java:1421)
We also observe huge number of warning messages.
Image decoding logging dropped!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment