ITmob-Ly
发布于 2024-01-15 / 77 阅读
0

Android Exception - IllegalArgumentException: Too many RemoteViews in constructor

异常信息

当使用 GlanceAppWidget 实现 Widget 时得到如下错误信息:

GlanceAppWidget         cn.itmob.demo                 E  Error in Glance App Widget

java.lang.IllegalArgumentException: Too many RemoteViews in constructor
    at android.widget.RemoteViews.<init>(RemoteViews.java:3682)
    at androidx.glance.appwidget.Api31Impl.createRemoteViews(RemoteViewsTranslator.kt:100)
    at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateComposition(RemoteViewsTranslator.kt:129)
    at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateComposition-KpG6l20(RemoteViewsTranslator.kt:76)
    at androidx.glance.appwidget.AppWidgetSession.processEmittableTree(AppWidgetSession.kt:132)
    at androidx.glance.appwidget.AppWidgetSession$processEmittableTree$1.invokeSuspend(Unknown Source:15)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

异常原因

因为使用 GlanceAppWidgetSizeMode.Responsive 为多个尺寸的小部件定义UI,实现响应式布局时,提供了过多的不同尺寸下的视图。

Widget 的响应式布局是通过 RemoteViews 在 Android 12 (API 级别 31) 中新增的构造函数实现的,它接受一个包含视图大小和布局映射关系的 Map 集合作为参数,来为 RemoteViews 提供更好的显示效果。

RemoteViews 中可以在构造函数中指定的 RemoteView 的最大数量是 16,超过会抛出 IllegalArgumentException 异常。

/**
 * Create a new RemoteViews object that will inflate the layout with the closest size
 * specification.
 *
 * The default remote views in that case is always the one with the smallest area.
 *
 * If the {@link RemoteViews} host provides the size of the view, the layout with the largest
 * area that fits entirely in the provided size will be used (i.e. the width and height of
 * the layout must be less than the size of the view, with a 1dp margin to account for
 * rounding). If no layout fits in the view, the layout with the smallest area will be used.
 *
 * @param remoteViews Mapping of size to layout.
 * @throws IllegalArgumentException if the map is empty, there are more than
 *   MAX_INIT_VIEW_COUNT layouts or the remote views are not all from the same application.
 */
public RemoteViews(@NonNull Map<SizeF, RemoteViews> remoteViews) {
    if (remoteViews.isEmpty()) {
        throw new IllegalArgumentException("The set of RemoteViews cannot be empty");
    }
    if (remoteViews.size() > MAX_INIT_VIEW_COUNT) {
        throw new IllegalArgumentException("Too many RemoteViews in constructor");
    }
    if (remoteViews.size() == 1) {
        // If the map only contains a single mapping, treat this as if that RemoteViews was
        // passed as the top-level RemoteViews.
        RemoteViews single = remoteViews.values().iterator().next();
        initializeFrom(single, /* hierarchyRoot= */ single);
        return;
    }
    mClassCookies = initializeSizedRemoteViews(
            remoteViews.entrySet().stream().map(
                    entry -> {
                        entry.getValue().setIdealSize(entry.getKey());
                        return entry.getValue();
                    }
            ).iterator()
    );
    RemoteViews smallestView = findSmallestRemoteView();
    mApplication = smallestView.mApplication;
    mLayoutId = smallestView.mLayoutId;
    mViewId = smallestView.mViewId;
    mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
    configureDescendantsAsChildren();
}

更多关于 Widget 的响应式布局可以参见官方文档:

https://developer.android.com/develop/ui/views/appwidgets/layouts#provide-responsive-layouts

https://developer.android.com/jetpack/compose/glance/build-ui?hl=en#sizemode-responsive