Android进阶知识(十六):理解RemoteViews
Android进阶知识(十六):理解RemoteViews
一、RemoteViews及其应用
RemoteViews表示的是一个View结构,一种远程View,它可以在其它进程中显示,由于它在其他进程中显示,为了能够更新它的界面,RemoteViews提供了一组基础的操作用于跨进程更新它的界面。
RemoteViews在Android中的使用场景有两种:通知栏和桌面小部件。
通知栏主要是通过NotificationManager的notify方法来实现,它除了默认效果外,还可以另外自定义布局(这就是RemoteView的应用)。桌面小部件则是通过AppWidgetProvider来实现的,AppWidgetProvider本质上是一个广播。
关于如何使用RemoteViews应用到通知栏和桌面小部件,读者可以参看博客:RemoteViews在桌面小部件和通知栏的使用
。
通知栏和桌面小部件的开发过程中会用到RemoteViews,它们在更新界面时,由于二者的界面运行在系统的SystemServer进程中,为了跨进程更新界面,RemoteViews提供了一些了set方法。
二、RemoteViews支持的View与提供的set方法
RemoteViews的作用是在其他进程中显示并更新View界面。RemoteViews目前并不能支持所有的View类型,其支持的所有类型如下表所示。
Layout | View |
---|---|
FrameLayout、LinearLayout、RelativeLayout、GridLayout | AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewStub |
RemoteViews没有提供findViewById方法,因此无法直接访问里面的View元素,而必须通过RemoteViews所提供的一系列set方法来完成,这是因为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的图片资源 |
setImageViewBitmap(int viewId, Bitmap bitmap) | 设置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 |
RemoteViews的大部分set方法都是通过反射来完成的。
三、RemoteViews的内部机制
通知栏和桌面小部件分别由NotificationManager和AppWidgetManager管理,而这两者通过Binder分别和SystemServer进程中的NotificationManagerServer以及AppWidgetServer进行通信。
由此可见,通知栏和桌面小部件的布局文件实际上是在NotificationManagerServer以及AppWidgetServer中被加载的,而它们运行在系统的SystemServer中,这就与原进程构成了跨进程通信的场景。
RemoteViews的内部机制如图所示。
RemoteViews内部机制的运行步骤为:
- RemoteViews通过Binder传递到SystemServer进程
由于RemoteViews实现了Parcelable接口,因此可以跨进程传输,系统会根据RemoteViews中的包名等信息去得到该应用的资源。
-
通过LayoutInflater去加载RemoteViews中的布局文件
-
系统对View执行一系列界面更新任务
这些任务是通过set方法提交的。set方法对View所做的更新并不是立即执行的,在RemoteViews内部会记录所有的更新操作,具体的执行时机要等到RemoteViews被加载以后才能执行。
当需要更新RemoteViews时,需要调用一系列set方法并通过NotificationManager和AppWidgetManager来提交更新任务,具体的更新操作也是在SystemServer进程中完成的。
从理论上来说,系统完全可以通过Binder去支持所有的View和View操作。那为啥不用这种方式呢?
这种方式,由于View的方法太多,代价太大,而且大量的IPC操作会影响效率。因此Android系统提供了Action的概念,Action同样实现了Parcelable接口,封装了具体的操作,然后传输到远程SystemServer进程中。
四、RemoteViews的意义
RemoteView主要是提供了进程间View更新的一种高效快速的解决方案,主要应用在Notification 和 AppWidgetProvider中。
参考资料:《Android开发艺术探索》