0%

理解 RemoteViews(二):RemoteViews 的内部机制

1. RemoteViews 所支持的 View 的类型

  • RemoteViews 目前并不能支持所有的 View 类型,它所支持的所有的类型如下:

    Layout View
    FrameLayoutLinearLayoutRelativeLayoutGridLayout AnalogClockButtonChronometerImageButtonImageViewProgressBarTextViewViewFlipperListViewGridViewStackViewAdapterViewFlipperViewStub
  • RemoteViews 不支持上面所列 View 的子类及其他 View 类型,包括自定义类型 View 也不支持。比如如果在通知栏的 RemoteViews 中使用系统的 EditText,那么通知栏消息将无法弹出且会抛出异常

2. RemoteViews 常用的 set 方法

方法名 作用
setTextViewText(int viewId, CharSequence text) 设置 TextView 的文本
setTextViewTextSize(int viewId, int units, float size) 设置 TextView 的字体大小
setTextColor(int viewId, int color) 设置 TextView 的字体颜色
setImageViewResource(int viewId, int srcId) 设置 ImageView 的图片资源
setInt(int viewId, String methodName, int value) 反射调用 View 对象的参数类型为 int 的方法
setLong(int viewId, String methodName, long value) 反射调用 View 对象的参数类型为 long 的方法
setBoolean(int viewId, String methodName, boolean value) 反射调用 View 对象的参数类型为 boolean 的方法
setOnClickPendingIntent(int viewId, PendingIntent pendingIntent) 为 View 添加单击事件,事件类型只能为 PendingIntent

3. RemoteViews 的内部机制

  • RemoteViews 主要作用于通知栏桌面小部件,以这两个为例

  • 通知栏和桌面小部件分别由 NotificationManagerAppWidgetManager 管理,而 NotificationManagerAppWidgetManager 通过 Binder 分别和 SystemServer 进程中的 NotificationManagerService 以及 AppWidgetService 通信

  • 由此,通知栏和桌面小部件中的布局文件实际上是在 NotificationManagerServiceAppWidgetService 中被加载的,而它们运行在系统的 SystemServer 中,这就和我们的进程构成了跨进程通信的场景

    1. 首先 RemoteViews 会通过 Binder 传递到 SystemServer 进程,这是因为 RemoteViews 实现了 Parcelable 接口,因此它可以跨进程传输,系统会根据 RemoteViews 中的包名等信息去得到该应用的资源
    2. 然后会通过 LayoutInflater 去加载 RemoteViews 中的布局文件,在 SystemServer 进程中加载后的布局文件是一个普通的 View,只不过相对于我们的进程它是一个 RemoteViews 而已
    3. 接着系统会对 View 执行一系列的界面更新任务,这些任务就是之前我们通过 set 方法来提交的。set 方法对 View 所做的更新不是立刻执行的,在 RemoteViews 内部会记录所有的更新操作,具体的执行要等到 RemoteViews 被加载以后才能执行,这样 RemoteViews 就可以在 SystemServer 进程中显示了,这就是我们所看到的通知栏消息或者桌面小部件
    4. 当需要更新 RemoteViews 时,我们需要调用一系列的 set 方法并通过 NotificationManager 和 AppWidgetManager 来提交更新任务,具体的更新操作也是在 SystemServer 进程中完成的
  • RemoteViews 内部机制示意图

    RemoteViews 内部机制示意图

  • 关于单击事件,RemoteViews 只支持发起 PendingIntent,不支持 onClickListener 那种模式

  • setOnClickPendingIntentsetPendingIntentTemplate 以及 setOnClickFillInIntent 之间的区别和联系

    • setOnClickPendingIntent 用于给普通 View 设置单击事件,但是不能给集合(ListView 和 StackView)中的 View 设置单击事件,因为开销比较大,所以系统禁止了这种方式
    • 如果要给 ListView 和 StackView 中的 item 添加单击事件,必须将 setPendingIntentTemplatesetOnClickFillInIntent 组合使用才可以
-------------------- 本文结束感谢您的阅读 --------------------