[置顶] 安卓学习笔记之RemoteViews

1 RemoteViews的两种应用

1 桌面widget小部件( 使用戳这里)

2 通知栏通知信息

2 RemoteViews应用之通知栏信息

2.1 通知栏通知示例

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
            remoteViews = new RemoteViews(getPackageName(), R.layout.remoteviews_item_dl);
            remoteViews.setTextViewText(R.id.tv_filename, getPackageName()); // 设置标题
//            remoteViews.setTextViewText(R.id.tv_content, "this is notification"); // 设置内容
            Intent btIntent = new Intent();
            btIntent.setAction("com.yu.sendnotification.action_dl");
            PendingIntent btPendingIntent = PendingIntent.getBroadcast(this, 1, btIntent, PendingIntent.FLAG_CANCEL_CURRENT); // 发送广播意图
            remoteViews.setOnClickPendingIntent(R.id.bt_stop, btPendingIntent); // 设置点击事件
            Intent intent = new Intent(this, NewActivity.class);
            PendingIntent pi = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            noti = new Notification.Builder(context).setSmallIcon(R.mipmap.ic_launcher)
            .setTicker("Hellonotification")
            .setWhen(System.currentTimeMillis())
            .setAutoCancel(true)
            .setContentIntent(pi).build();
            manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.notify(0, noti);
               }

2.2 通知栏通知使用步骤

  • 1 通过Notification.Builder创建一个builder对象

     Notification.Builder builder = new Notification.Builder(context);
    
  • 2 给builder设置相关选项

            setContent(remoteViews)  // 设置RemoteViews
            setContentIntent(intent)   // 设置view的intent事件
            setContentText()        // 设置内容文字
            setContentTitle()       //设置标题文字
            setAutoCancel(bool) //设置自动取消
            setSmallIcon().         //设置小图标
            setTicker(CharSequence tickerText)  // 设置新消息状态栏滚动文字
            setDeleteIntent(PendingIntent intent) // 设置用户滑动删除通知intent
            setProgress(int max,int progress,boolean indeterminate) //设置进度
            setWhen(long when)   // 设置发送时间
            setSound(Uri sound):设定一个铃声,用于在通知的时候响应。传递一个Uri的参数,格式为“file:///mnt/sdcard/Xxx.mp3”。
            setLights(int argb, int onMs, int offMs):设定前置LED灯的闪烁速率,持续毫秒数,停顿毫秒数。
            setVibrate(long[] pattern):设定震动的模式,以一个long数组保存毫秒级间隔的震动。
            setDefaults(int)方法设定默认响应参数,在Notification中,对它的参数使用常量定义了,我们只需使用即可:
                            --DEFAULT_ALL:铃声、闪光、震动均系统默认。
                            --DEFAULT_SOUND:系统默认铃声。
                            --DEFAULT_VIBRATE:系统默认震动。
                            --DEFAULT_LIGHTS:系统默认闪光。
    
    
                需要权限
                <!-- 闪光灯权限 -->
                <uses-permission android:name="android.permission.FLASHLIGHT"/>
                <!-- 振动器权限 -->
                <uses-permission android:name="android.permission.VIBRATE"/>
    
  • 3 builder.build() 创建一个Notification对象

  • 4 获取NotificationManger并发送通知

    manager=(NotificationManager)=getSystemService(Context.NOTIFICATION_SERVICE);
    manager.notify(0, noti); 
    

3 了解PendingIntent

PendingIntent表示即将发生的意图,在RemoteViews的应用中起着非常关键的作用。

3.1 PendingIntent作用

1)  intent是即时发生的意图,PendingIntent不确定发生时间的意图
2)  用于给RemoteViews添加点击事件
3)  PendingIntent支持启动Activity、启动Service,发送广播三种意图,对应如下方法

[置顶] 安卓学习笔记之RemoteViews_第1张图片

3.2 三种意图参数

(Context context, int requestCode, Intent intent, int flags) 
requestCode表示请求码Private request code for the sender
flags标志,有4种
intent 意图

3.3 flags参数的意义

  • 1 FLAG_CANCEL_CURRENT:如果当前系统中已经存在一个相同的PendingIntent对象,
    那么就将先将已有的PendingIntent取消,然后重新生成一个PendingIntent对象。

  • 2 FLAG_NO_CREATE:如果当前系统中不存在相同的PendingIntent对象,
    系统将不会创建该PendingIntent对象而是直接返回null。

  • 3 FLAG_ONE_SHOT:该PendingIntent只作用一次。在该PendingIntent对象通过send()方法触发过
    后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException。

  • 4 FLAG_UPDATE_CURRENT:如果系统中有一个和你描述的PendingIntent对等的PendingInent,
    那么系统将使用该PendingIntent对象,但是会使用新的Intent来更新之前PendingIntent中的Intent对象数据,
    例如更新Intent中的Extras。

3.4 PendingInent的匹配规则

    两个PendingInent相同条件:requestCode与Intent都相同 
    Intent相同指Component与intent-filter相同(与Extras无关) 

3.5 id与flags对通知更新的影响

manager.notify(id, notification)发通知 
    1、当id相同时,后面的通知覆盖原来
    2、当id不同时
        --当PendingIntent不匹配时, 通知间不互相干扰,不受flags影响
        --当PendingIntent匹配时,按flags分析
            *使用FLAG_ONE_SHOT:后续的PendingIntent会和第一条保持一致,包括Extras,单击任意一条后,其他无法打开
            *使用FLAG_CANCEL_CURRENT:只有最新的通知可以打开
            *使用FLAG_UPDATE_CURRENT:之前弹出的通知中的PendingIntent都会被更新,包括Extras,并且通知都可以打开

4 RemoteViews的内部原理

4.1 常用构造函数

public RemoteViews(String packageName, int layoutId)

4.2 支持的View类型 (不支持自定义View类型)

layout:

    FrameLayout  LinearLayout  RelativeLayout  GridLayout

View:

AnalogClock button Chronometer ImageButton ImageView ProgressBar TextView ViewFlipper ListView GridView

4.3 常用set方法(跨进程显示view,无法使用findViewById方法)

  • setTextViewText(int viewId,CharSequence text) 设置TextView的文本内容 第一个参数是TextView的id 第二个参数是设置的内容
  • setTextViewTextSize(int viewId,int units,float size) 设置TextView的字体大小 第二个参数是字体的单位
  • setTextColor(int viewId,int color) 设置TextView字体颜色
  • setImageViewResource(int viewId,int srcId) 设置ImageView的图片
  • setInt(int viewId,String methodName,int value) 反射调用View对象的参数类型为Int的方法 比如上述的setImageViewResource的方法内部就是这个方法实现 因为srcId为int型参数
  • setLong setBoolean 类似于setInt
  • setOnClickPendingIntent(int viewId,PendingIntent pendingIntent) 添加点击事件的方法,事件类型只能为PendingIntent
    还有很多方法,大部分是通过反射调用View的方法。反射不了解的可以猫一眼Java反射机制

4.4 RemoteVews内部机制

4.4.1运行环境

  • NotificationManger与AppWidgetManger通过Binder分别和运行于SystemServer的NotificationMangerService与AppWidgetMangerService进行通信
  • 通知栏和桌面小部件的布局分别在NotificationMangerService与AppWidgetMangerService被加载(两者运行于SystemServer)

如下图所示

[置顶] 安卓学习笔记之RemoteViews_第2张图片

4.4.2 执行流程

  • 1 RemoteViews通过Binder传递至SystemServer进程(因为RemoteViews实现了Parcelable接口,因此它可以跨进程传输)

  • 2 系统根据RemoteViews中的packageName, layoutId去得到该应用的资源,之后通过LayoutInflater去加载RemoteViews中的布局文件 (在SystemServer中加载的是一个普通的View,只不过相对于我们的进程他是一个RemoteView而已)

  • 3 系统对View界面执行一系列的更新操作,即通过set方法提交的,但更新操作不是立即执行(在RemoteViews内部会记录所有的更新操作),而是到RemoteViews被加载后执行

  • 4 RemoteViews显示后,再次更新时,则调用set方法并通过NotificationManger与AppWidgetManger来提交更新任务,具体更新操作在SystemServer中完成

  • 5 每一次的set操作对应着一个action (对应着一个view操作,实现了Parcelable接口),RemoteViews会添加一个对应的action对象 ,当这些更新操作被提交时,这些action会被跨进程传输到远程进程中并在远程进程执行。远程进程通过RemoteViews的apply方法进行view的更新操作(apply内部回去遍历所有的action并执行action的apply方法),通知栏和桌面小插件在初始化界面时调用apply,后续更新界面会调用reapply。如图示
    [置顶] 安卓学习笔记之RemoteViews_第3张图片

4.5 单击事件的使用

  • RemoteViews中只支持发起PendingIntent,不支持onClickListener模式

    例:
    Intent btIntent = new Intent();
    btIntent.setAction("com.yu.sendnotification.action_dl");
    PendingIntent btPendingIntent = PendingIntent.getBroadcast(this, 1, btIntent, PendingIntent.FLAG_CANCEL_CURRENT);
            remoteViews.setOnClickPendingIntent(R.id.bt_stop, btPendingIntent);//给id为stop的view设置点击事件
    
  • setPendingIntentTemplatey与setOnClickFillInIntent须结合,给ListView和StackView中的item添加点击事件

4.6 使用RemoteViews的好处

  • 1.不需要定义大量的Binder接口
  • 2.通过在远程进程中批量执行RemoteViews的修改操作从而避免了大量的IPC操作这就提高了程序性能
  • 3.只需要操作RemoteViews即可实现效果,操作简单

5 AIDL和RemoteView的应用场景

  • 1 一个应用简单的更新另一个应用的界面,可以选择AIDL去实现。但对界面的更新比较频繁,这个时候就会有效率问题,同时AIDL接口就有可能使问题复杂化,此时不宜使用aidl

  • 2 对于界面更新比较频繁,适宜采用RemoteView来实现就,当然remoteView也有点缺点,remoteView仅支持一些常见的View,不支持自定View

后记:此篇为总结篇,作了个人梳理。参照了安卓开发艺术探索相关内容。

你可能感兴趣的:(android,通知,widget,RemoteView)