异常信息
当使用 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)
异常原因
因为使用 GlanceAppWidget
的 SizeMode.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