android进阶(五)-----理解RemoteViews

269 阅读4分钟

一、RemoteView的应用

RemoteView主要用在通知栏和桌面小部件的开发

1、RemoteView在通知栏上的应用

(1)使用系统默认的样式弹出一个通知栏,代码实例:

Notification notification = new Notification(); 
notification.icon = R.drawable.ic_launcher; 
notification.tickerText = "hello" 
notification.when = System.currentTimeMillis(); 
notification.flags = Notification.FLAG_AUTO_CANCEL; 
Intent intent = new Intent(this,MainActivity.class); 
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT); 
notification.setLatestEventInfo(this,"aaa","bbbb",pendingIntent); 
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); 
manager.notify(1,notification);

(2)通过RemoteView自定义通知栏布局文件

Notification notification = new Notification(); 
notification.icon = R.drawable.ic_launcher; 
notification.tickerText = "hello" 
notification.when = System.currentTimeMillis(); 
notification.flags = Notification.FLAG_AUTO_CANCEL; 
Intent intent = new Intent(this,MainActivity.class); 
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT); 
RemoteViews remoteViews = new RemoteViews(getPackageName(),R.layout.notification); 
remoteViews.setTextViewText(R.id.msg,"vvvv"); 
remoteViews.setImageViewResource(R.id.icon,R.drawable.icon1); 
PendingIntent openActivityPendingIntent = PendingIntent.getActivity(this,0,new Intent(this,MainActivity.class),PendingIntent.FLAG_UPDATE_CURRENT); 
remoteViews.setOnClickPendingIntent(R.id.open_activity2,openActivityPendingIntent); 
notification.contentView = remoteViews; 
notification.contentIntent = pendingIntent; 
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); 
manager.notify(2,notification);

2、RemoteViews在桌面小部件上的应用

AppWidgetProvider是android中用于实现桌面小部件的类,本质是一个广播

(1)定义小部件界面:widget.xml

<?xml version="1.0" encoding="utf-8"> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"         
    android:layout_width="match_parent"         
    android:layout_height="match_parent"         
    android:orientation="vertical">          
    <ImageView android:id="@+id/imageView1"                    
        android:layout_width="wrap_content"                    
        android:layout_height="wrap_content"                    
        android:src="@drawable/icon1"/> 
</LinearLayout>

(2)定义小部件配置信息:appwidget_provider_info.xml

initialLayout:初始化布局

updatePeriodMillis:自动更新周期,单位是毫秒

<?xml version="1.0" encoding="utf-8"> 
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"         
    android:initialLayout="@layout/widget"         
    android:minHeight="84dp"         
    android:minWidth="84dp"         
    android:updatePeriodMillis="86400000"> 
</appwidget-provider>

(3)定义小部件的实现类

public class AppWidgetProvider extends AppWidgetProvider{ 
    public static final String CLICK_ACTION = "com.test.test.action.CLICK"   
    public AppWidgetProvider(){     
        super(); 
    } 
    
    @Override 
    public void onReceive(final Context context,Intent intent){     
        super.onReceive(context,intent);     
        //这里判断自己的action,如被单击了     
        if(intent.getAction().equals(CLICK_ACTION)){         
            Toast.makeText(context,"click",Toast.LENGTH_SHORT).show();         
            new Thread(new Runnable(){             
                @Override             
                public void run(){                 
                    Bitmap srcbBitmap=BitmapFactory.decodeResource(context.getResources(),R.drawable.icon1);
                    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.getBroadcase(context,0,intentClick,0);                     
                        remoteViews.setOnClickPendingIntent(R.id.imageView1,pendingIntent);                     
                        appWidgetManager.updateAppWidget(new ComponentName(context,AppWidgetProvider.class),remoteViews);                     
                        SystemClock.sleep(30);                 
                    }             
                }         
            }).start();     
        } 
    } 
    /**
    *每次桌面部件更新时都调用一次该方法
    */ 
    @Override 
    public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds){     
        super.onUpdate(conte,appWidgetManager,appWidgetIds);     
        final int counter = appWidgetIds.length;     
        for(int i= 0; i < counter;i++){         
            int appWidgetId = appWidgetIds[i];         
            onWidgetUpdate(context,appWidgetManager,appWidgetId);     
        }
    } 
    /**
    * 桌面小部件更新
    */
    private void onWidgetUpdate(Context context,AppWidgetManager appWidgetManager,int appWidgetId){     
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget);     
        //桌面小部件点击事件发送Intent广播     
        Intent intentClick = new Intent();     
        intentClick.setAction(CLICK_ACTION);     
        PendingIntent pendingIntent = PendingIntent.getBroadcase(context,0,intentClick,0);     
        remoteViews.setOnClickPendingIntent(R.id.imageView1,pendingIntent);     
        appWidgetManager.updateAppWidget(appwidgetId,remoteViews); 
    }   
    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(),scrbBitmap.getHeight(),matrix,true);       
        return tmpBitmap;
    } 
}

(4)在AndroidManifest.xml中声明小部件

3、AppWidgetProvider方法:onUpdate、onEnabled、onDisabled、onDeleted和onReceive

onEnable:当窗口小部件第一次添加到桌面时调用,可添加多次但只在第一次调用

onUpdate:小部件被添加或者小部件更新时都会调用一次该方法,小部件更新时机由updatePeriodMillis来指定,每个周期小部件都会自动更新一次

onDeleted:每次删除一次桌面小部件就会调用一次

onDisabled:当最后一个该类型的桌面小部件被删除是调用该方法

onReceive:广播的内置方法,用于分发具体的事件给其他方法

4、PendingIntent介绍

PendingIntent表示一种处于pending状态的意图,,而pending状态表示一种待定、等待、即将发生的意思。

PendingIntent支持三种待定意图:启动Activity、启动Service和发送广播即:

getActivity(Context context,int requestCode,Intent intent,int flags)获得一个PendingIntent,该待定意图发生时,相当于Context.startActivity(intent)

getService(Context context,int requestCode,Intent intent,int flags)获得一个PendingIntent,该待定意图发生时,相当于Context.startService(intent)

getBroadcast(Context context,int requestCode,Intent intent,int flags)获得一个PendingIntent,该待定意图发生时,相当于Context.sendBroadcase(intent)

flags常见类型有:

FLAG_ONE_SHOT:PendingIntent只能被使用一次,然后会被自动cancel

FLAG_NO_CREATE:PendiingIntent不会主动创建,如果不存在,那么getActivity、getService和getBroadcast会直接返回null。

FLAG_CANCEL_CURRENT:PendingIntent如果存在,那么他们会被cancel,然后系统会创建一个新的PendingIntent。

FLAG_UPDATE_CURRENT:PendingIntent如果存在,那么他们会被更新。

二:RemoteView的内部机制

1、RemoteView的作用是在其他进程中显式并更新View界面。先看一下他的构造方法:

public RemoteView(String packageName,int layoutId),一个表示包名,第二个表示布局文件

RemoteView不支持所有View类型,只支持:FrameLayout、LinearLayout、RelativeLayout、GridLayout、AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewStub。

RemoteView不支持他们子类和其他View类型,无法使用自定义View

2、RemoteViews的set方法

RemoteViews没有提供findViewById方法,无法直接访问里面的View,必须通过set方法

setTextViewText:设置TextView的文本

setTextViewTextSize:设置TextView的字体大小

setTextColor:设置TextView的字体颜色

setImageViewResource:设置ImageView的图片资源

setInt:反射调用View对象的参数类型为int的方法

setLong:反射调用View对象的参数类型为long的方法

setBoolean:反射调用View对象的参数类型为boolean的方法

setOnClickPendingIntent:为View添加单击事件,事件类型只能为PendingIntent

3、RemoteViews的内部机制

通知栏和桌面小部件分别由NotificaionManager和AppWidgetManager管理,而NotificaionManager和AppWidgetManager通过Binder分别和SystemServer进程中的NotificationManagerService以及AppWidgetService进行通信。

RemoteViews通过Binder传递到SystemServer进程,因为RemoteViews实现了Parcelable接口,所以可以跨进程传输,系统根据RemoteViews中的包名去得到该应用的资源,然后通过LayoutInflater去加载RemoteViews中的布局文件