RemoteViews的作用和工作原理

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);

运行效果如下:

RemoteViews的作用和工作原理_第1张图片

点击会打开一个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的作用和工作原理_第2张图片

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的作用和工作原理_第3张图片

最后用一张图来说明RemoteViews的内部机制

RemoteViews的作用和工作原理_第4张图片

你可能感兴趣的:(Android学习笔记)