06. RemoteViews
RemoteViews
RemoteViews 支持的控件
小组件本身是基于 RemoteViews,所以仅支持有限的组件与布局类型,且不支持自定义组件。
RemoteViews
仅限于支持以下布局:
- AdapterViewFlipper
- FrameLayout
- GridLayout
- GridView
- LinearLayout
- ListView
- RelativeLayout
- StackView
- ViewFlipper
以及以下小部件:
从 API 31 (Android 12) 开始,还可以使用以下小部件和布局:
不支持这些类的后代。
RemoteViews
还支持 ViewStub
,这是一个不可见的、零大小的 View
,您可以使用它在运行时延迟扩展布局资源。
Ref:
[RemoteViews Android Developers](https://developer.android.com/reference/android/widget/RemoteViews)
RemoteViews 添加自定义 View
如果想要在 Widget
中使用自定义 View
,可以通过以下方式实现:
1
2
3
4
5
6
7
8
9
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
MyCustomView customView = new MyCustomView(context);
customView.measure(width, height);
customView.layout(0, 0, width, height);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
customView.draw(new Canvas(bitmap));
remoteViews.setImageViewBitmap(R.id.bitmap, bitmap);
// 实际上就是将自定义 `View` 在 `Bitmap` 上绘制,然后通过 `ImageView` 进行展现。
RemoteViews 原理
RemoteViews 概述
RemoteViews 是一个用来描述 view 的 hierarchy,其能在其它进程展示。hierarchy 通过能一个 layout 中 inflate 出来,提供了一些基本的操作改变 hieraychy。
RemoteViews 只能有限的支持部分布局和 View。
RemoteViews 并不是真正的 View,它储存着构建 View 所需的信息,使用 Widget 的进程获取到 RemoteViews 后就可以构建 Widget 了。
RemoteViews 序列化
RemoteViews 要实现 IPC 传递,必然是可序列化的:
1
2
3
public class RemoteViews implements Parcelable, Filter {
}
aidl 中定义
1
2
3
4
// frameworks/base/core/java/android/widget/RemoteViews.aidl
package android.widget;
parcelable RemoteViews;
可以在服务中 IPC 传递:
1
2
// frameworks/base/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
void updateAppWidgetIds(String callingPackage, in int[] appWidgetIds, in RemoteViews views);
RemoteViews 原理
RemoteViews 通常用在 Notification
和 Widget
中,分别通过 NotificationManager
和 AppWidgetManager
来进行管理,它们则是通过 Binder
来和 SystemServer
进程中的 NotificationManagerService
以及 AppWidgetService
进行通信,所以,RemoteViews 实际上是运行在 SystemServer
中的,我们在修改 RemoteViews 时,就需要进行跨进程通信了,而 RemoteViews 封装了一系列跨进程通信的方法,简化了我们的调用,这也是为什么 RemoteViews 不支持全部的 View 方法的原因,RemoteViews 抽象了一系列的 set 方法,并将它们抽象为统一的 Action 接口,这样就可以提供跨进程通信的效率,同时精简核心的功能。