Android 第二十八周

一、理解 RemoteViews

1.RemoteViews 是一种 View 结构,可以在其它进程中显示,所以为了更新它的界面,RemoteViews 自身提供了一些方法用于跨进程更新它的界面
2.RemoteViews 在 Android 中使用场景有两种:通知栏、桌面小部件

二、RemoteViews 的应用

2.1 RemoteViews 在通知栏上的应用

系统提供了默认的通知栏样式,同时也使用自定义布局样式构建自定义通知,满足个性化需求

Notification notification = new Notification();
notification.icon = R.drawable.ic_launcher;
notification.tickerText = "hello world";
notification.when = System.currentTimeMillis();
notification.flags = Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(this, DemoActivity_1.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// 第一个参数:包名;第二个参数:布局文件 id
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_notification);
// 设置文本
remoteViews.setTextViewText(R.id.msg, "chapter_5");
// 设置图片
remoteViews.setImageViewResource(R.id.icon, R.drawable.icon1);
PendingIntent openActivity2PendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, DemoActivity_2.class), PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.open_activity2, openActivity2PendingIntent);
notification.contentView = remoteViews;
notification.contentIntent = pendingIntent;
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(2, notification);

2.2 RemoteViews 在桌面小部件上的应用

开发步骤:
1. 定义小部件界面
2. 定义小部件配置信息
3. 定义小部件的实现类
4. 在 AndroidManifest.xml 中声明小部件

桌面小部件通过 AppWidgetProvider 来实现,本质是一个广播,继承自 BroadCastReceiver,可以把 AppWidgetProvider 当成一个 BroadcastReceiver 即可

AppWidgetProvider 会自动根据广播的 Action 通过 onReceive 来分发广播,也就是调用上述几个方法。这几个方法的调用时机如下所示
● onEnable:当该窗口小部件第一次添加到桌面时调用该方法,可添加多次但只在第一次调用。
● onUpdate:小部件被添加时或者每次小部件更新时都会调用一次该方法,小部件的更新时机由 updatePeriodMills 来指定,每个周期小部件都会自动更新一次。
● onDeleted:每删除一次桌面小部件就调用一次。
● onDisable:当最后一个该类型的桌面小部件被删除时调用该方法,注意是最后一个。
● onReceive:这是广播的内置方法,用于分发具体的事件给其他方法。

桌面小部件的界面初始化和界面更新都需要通过 RemoteViews 来完成

三、RemoteViewa 的内部机制

首先看一下它的构造方法,这里只介绍一个最常用的构造方法:public RemoteViews(String packageName, int layoutId),它接受两个参数,第一个表示当前应用的包名,第二个参数表示待加载的布局文件,这个很好理解。RemoteViews 目前并不能支持所有的 View 类型,它所支持的所有类型如下:
Layout
FrameLayout、LinearLayout、RelativeLayout、GridLayout。
View
AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewStub。
上面所描述的是 RemoteViews 所支持的所有的 View 类型,RemoteViews 不支持它们的子类以及其他 View 类型,也就是说 RemoteViews 中不能使用除了上述列表中以外的 View,也无法使用自定义 View。比如如果我们唉通知栏的 RemoteViews 中使用系统的 EditText,那么通知栏消息将无法弹出并且会抛异常

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

猜你喜欢

转载自blog.csdn.net/qq_21586317/article/details/81434950