文章

06. RemoteViews

06. RemoteViews

RemoteViews

RemoteViews 支持的控件

小组件本身是基于 RemoteViews,所以仅支持有限的组件与布局类型,且不支持自定义组件。

RemoteViews 仅限于支持以下布局:

以及以下小部件:

从 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 通常用在 NotificationWidget 中,分别通过 NotificationManagerAppWidgetManager 来进行管理,它们则是通过 Binder 来和 SystemServer 进程中的 NotificationManagerService 以及 AppWidgetService 进行通信,所以,RemoteViews 实际上是运行在 SystemServer 中的,我们在修改 RemoteViews 时,就需要进行跨进程通信了,而 RemoteViews 封装了一系列跨进程通信的方法,简化了我们的调用,这也是为什么 RemoteViews 不支持全部的 View 方法的原因,RemoteViews 抽象了一系列的 set 方法,并将它们抽象为统一的 Action 接口,这样就可以提供跨进程通信的效率,同时精简核心的功能。

本文由作者按照 CC BY 4.0 进行授权