理解RemoteViews
RemoteViews在十几开发中,主要用于在通知栏和桌面小部件的开发过程中。
RemoteViews在通知栏上的作用
1.RemoteViews主要是用于视自定义通知。
发送系统默认通知:
private void postNotify() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
Intent i = new Intent(this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(this, 0, i,
PendingIntent.FLAG_UPDATE_CURRENT);
//设置挂起的pendingIntent
builder.setContentIntent(intent);
// 贴标会出现在顶部状态栏一下
builder.setTicker("你瞅啥?");
// 设置贴标的小图标
builder.setSmallIcon(R.mipmap.ic_launcher);
//点击时取消通知
builder.setAutoCancel(true);
/**设置通知栏显示IDE大图标*/
// builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
/**设置内容标题*/
builder.setContentTitle("我是大标题啊");
/**设置内容文本*/
builder.setContentText("我是文本内容");
/**设置****小的文本*/
builder.setSubText("我是附加文本内容");
// 构建通知
Notification notification = builder.build();
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify(0, notification);
}
发送自定义通知:
通过RemoteViews 加载自定义通知布局来改变系统默认样式。
private void postCustomNotify() {
Notification fication = new Notification();
fication.icon = R.mipmap.ic_launcher;
fication.tickerText = "您有新短消息,请注意查收";
fication.when = System.currentTimeMillis();
fication.flags = Notification.FLAG_AUTO_CANCEL;
Intent intent1 = new Intent(this, MainActivity.class);
PendingIntent pd = PendingIntent.getActivity(this, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
/**通过RemoteViews加载布局,首先new出一个对象,传入包名和布局id*/
RemoteViews rv = new RemoteViews(getPackageName(), R.layout.custom_notify);
/**设置数据,第一个参数为控件id,第二个参数为属性值*/
rv.setImageViewResource(R.id.iv_icon, R.mipmap.ic_launcher);
rv.setTextViewText(R.id.tv_content_title, "我是自定义标题");
rv.setTextViewText(R.id.tv_content_c, "我是自定义内容");
PendingIntent openActivity = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
/**给布局中的控件添加点击事件*/
rv.setOnClickPendingIntent(R.id.iv_icon, openActivity);
fication.contentView = rv;
fication.contentIntent = pd;
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(1, fication);
}
RemoteViews在桌面小组件上的使用
AppWidgetProvider是Android中提供的用于实现桌面小部件的类,本质上是一个广播。
开发步骤:
(1)定义小部件界面(布局界面xml)
(2)定义小部件配置信息(res/xml下新建xx.xml文件)
(3)定义小部件的实现类(继承自AppWidgetProvider)
(5)在AndroidMainfest.xml文件中声明小部件
AppWidgetProvider有几个重要的回调方法:
onEnable:当该窗口小部件第一次添加到桌面时调用该方法,可添加多次但只在第一次调用。
onUpdate:小部件被添加时或者每次小部件更新时,都会调用一次该方法,小部件的更新时机由updatePeriodMillis来指定,每个周期小部件都会自动更新一次。
onDeleted:每删除一次桌面小部件就调用一次。
onDisable:当最后一个该类型的桌面小部件被删除时调用该方法,注意是最后一个。
onReceive:这个是广播的内置方法,用于分发具体的事件给其他方法。
PendingIntent概述
PendingIntent表示一种处于pending状态的意图,而pending状态表示的是一种待定,等待,即将发生的意思,就是说,接下来会有一个Intent(意图)在将来的某个时刻发生。
PendingIntent是即将发生,而Intent是立即发生。
1、PendingIntent 典型的使用场景就是和RemoteViews的点击事件配合使用;
2、支持三种待定Intent:Activity,Service和Broadcast
3、PendingIntent相同的定义:内部的Intent和requestCode都相同。Intent相同的定义:两个Intent的componentName和intent-filter相同(不包括extras)
4、flag定义:
FLAG_NO_CREATE:不会主动创建,如果当前PendingIntent之前不存在,那么获取getActivity()、getService()、getBroadCast会返回null。基本不会使用。
FLAG_ONE_SHOT:以第一个为准,后续的会全部和第一条保持一致,任意一条被处罚,其他的都cancel
FLAG_CANCEL_CURRENT:前面的相同的PendingIntent都会被cancel,只有最新的可用。
FLAG_UDPATE_CURRENT:前面的PendingIntent都会被更新(它们Intent中的extras都会被更新)
RemoteViews的内部机制
RemoteViews的作用是在其他进程中显示并更新View界面。
构造方法:第一个参数为当前应用的包名,第二个参数表示待加载的布局文件。
public RemoteViews(String packageName, int layoutId) {
throw new RuntimeException("Stub!");
}
RemoteViews支持的Layout类型:
FrameLayout、LinearLayout、RelativeLayout、GridLayout
RemoteViews支持的View类型:
AnalogClock, Button, Chronometer, ImageButton, ImageView, ProgressBar, TextView, ViewFlipper, ListView, GridView, StackView, AdapterViewFlipper, ViewStub。
RemoteViews内部机制
由于RemoteViews主要用于通知栏和桌面小部件中。而通知栏和桌面小部件分别有NotifycationManager和AppWidgetManager管理,而NotifycationManager和AppWidgetManager通过Binder分别和SystemServer进程中的NotificationManagerService以及AppWidgetService进行通信。
简单归纳,客户端的remoteViews通过action对象,由binder机制来更新服务端的remoteViews,所以RemoteViews本身也实现了Parcelable接口。
RemoteViews中真正操作View的方法apply和reapply,前者会加载布局并更新界面,后者则只更新界面。
跨进程的RemoteViews传递
模拟通知栏的实现。注意不同应用间RemoteViews的id不同,需要约定名称然后重新通过Resource.getIdentifier来获取。