RemoteViews的基本概念
什么是RemoteViews呢?RemoteViews是一种远程View,它提供了一组基础的操作用于跨进程更新页面。RemoteViews主要有两个应用场景:自定义通知栏和桌面小部件。
1 自定义通知栏使用
首先我们看系统默认的通知栏的是怎么实现的:
Notification.Builder builder;
Intent intent;
NotificationManager manager;
Notification notification;
builder=new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setTicker("hello world");
builder.setContentText("测试");
builder.setWhen(System.currentTimeMillis());
intent=new Intent(this,DemoActivity_2.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
manager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notification=builder.build();
manager.notify(sId,notification);
运行效果如下:
点击会打开一个DemoActivity_2的activity。
在正常开发中我们需要对通知栏显示样式进行自定义,这时候就要用到RemoteViews,下面看RemoteViews自定义通知栏:
Notification.Builder builder;
Intent intent;
NotificationManager manager;
Notification notification;
builder=new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setTicker("hello world");
builder.setWhen(System.currentTimeMillis());
intent=new Intent(this,DemoActivity_1.class);
intent.putExtra("sid", "" + sId);
PendingIntent pendingIntent2=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
System.out.println(pendingIntent2);
RemoteViews remoteViews1=new RemoteViews(getPackageName(),R.layout.layout_notification);
remoteViews1.setTextViewText(R.id.msg,"zhe shi xinxi de "+sId);
remoteViews1.setImageViewResource(R.id.icon,R.mipmap.ic_launcher);
PendingIntent pendingIntent1=PendingIntent.getActivity(this,0,new Intent(this,DemoActivity_2.class),PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews1.setOnClickPendingIntent(R.id.open_activity2,pendingIntent1);
builder.setContent(remoteViews1);
builder.setContentIntent(pendingIntent2);
manager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notification=builder.build();
manager.notify(sId,notification);
layout_notification.xml代码:
运行效果如下:
RemoteViews使用很简单,只需要提供当前应用的包名和布局文件的资源ID就可以创建一个RemoteViews对象。在更新RemoteViews时,由于无法直接访问到RemoteViews里面的View,因为通知栏试运行在SystemServer进程中,所以如果需要更新RemoteViews必须要使用RemoteViews提供的一系列方法来更新View。具体的方法在下面会讲到。
2 桌面小部件的实现
Android提供AppWidgetProvider用于桌面小部件的实现,其本质就是一个广播。下面是一个具体的实现步骤:
第一、定义小部件页面:
widget.xml
里面放了一个小图片。
第二、定义小部件配置信息
配置信息放在res/xml下面:
配置信息主要作用:1.initialLayout用于绑定对应的需要初始化的布局;2.minHeight minWidth用于定义小部件的最小尺寸;3.updatePeriodMillis定义小部件自动更新的周期;4.minResizeWidth 和 minResizeHeight指定了 widget 的最小绝对尺寸。也就是说,如果 widget 小于该尺寸,便会因为变得模糊、看不清或不可用。 使用这两个属性,可以允许用户重新调整 widget 的大小,使 widget 的大小可以小于 minWidth 和 minHeight。
3 定义小部件的实现类:
public class MyAppWidgetProvider extends AppWidgetProvider {
public static final String TAG="MyAppWidgetProvider";
public static final String CLICK_ACTION="com.my.learn.code.remoteviews.CLOCK";
public MyAppWidgetProvider(){
super();
}
/**
* 这是广播的内置方法,用于犯法具体的事件给其他方法
* @param context
* @param intent
*/
@Override
public void onReceive(final Context context, final Intent intent) {
super.onReceive(context, intent);
Log.v(TAG,"onReceive :action="+intent.getAction());
//这里判断是自己的ACTION,做自己的事情,比如小部件被点击后要做什么,这里是一个动画效果
if (intent.getAction().equals(CLICK_ACTION)){
Toast.makeText(context,"clicked it",Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
@Override
public void run() {
Bitmap srcbBitmap= BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
AppWidgetManager appWidgetManager=AppWidgetManager.getInstance(context);
for (int i=0;i<37;i++){
float degree=(i *10)%360;
RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.widget);
remoteViews.setImageViewBitmap(R.id.imageView1,rotateBitmap(context,srcbBitmap,degree));
Intent intentClick=new Intent();
intentClick.setAction(CLICK_ACTION);
PendingIntent pendingIntent=PendingIntent.getBroadcast(context,0,intentClick,0);
remoteViews.setOnClickPendingIntent(R.id.imageView1,pendingIntent);
appWidgetManager.updateAppWidget(new ComponentName(context,MyAppWidgetProvider.class),remoteViews);
SystemClock.sleep(30);
}
}
}).start();
}
}
private Bitmap rotateBitmap(Context context,Bitmap srcbBitmap,float degree){
Matrix matrix=new Matrix();
matrix.reset();
matrix.setRotate(degree);
Bitmap tmpBitmap=Bitmap.createBitmap(srcbBitmap,0,0,srcbBitmap.getWidth(),srcbBitmap.getHeight(),matrix,true);
return tmpBitmap;
}
/**
* 桌面小部件更新
* @param context
* @param appWidgetManager
* @param appWidgetId
*/
private void onWIdgetUpdate(Context context,AppWidgetManager appWidgetManager,int appWidgetId){
Log.v(TAG,"appWidgetId="+appWidgetId);
RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.widget);
//桌面小部件单击事件发送的Intent广播
Intent intentClick=new Intent();
intentClick.setAction(CLICK_ACTION);
PendingIntent pendingIntent=PendingIntent.getBroadcast(context,0,intentClick,0);
remoteViews.setOnClickPendingIntent(R.id.imageView1,pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId,remoteViews);
}
/**
* 每次桌面小部件更新时都调用一次该方法
*zhexie lianpifu doumeiyoud e huo
*
* 小部件的更新时机由updatePeriodMillis来指定,每个周期小部件都会自动更新一次
* @param context
* @param appWidgetManager
* @param appWidgetIds
*/
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
Log.v(TAG, "onUpdate");
final int counter=appWidgetIds.length;
Log.v(TAG, "counter = "+counter);
for (int i =0;i
4 在AndroidManifest.xml中声明小部件
RemoteViews的内部机制
RemoteViews作用是在其他进程中显示并更新View界面,RemoteViews构造方法: public RemoteViews(String packageName, int layoutId),需要两个参数:当前应用包名以及待加载的布局文件。目前RemoteViews并不能支持所有View类型,支持的View类型如下:
Layout
FrameLayout、LinearLayout、RelativeLayout、GridLayout
View
Button、ImageButton、ImageView、TextView、ListView、GridView、AnalogClock、Chronometer、ProgressBar、ViewFlipper、StackView、AdapterViewFlipper、ViewStub。
更新RemoteViews必须使用RemoteViews提供的一系列的set方法:
最后用一张图来说明RemoteViews的内部机制