一、什么是RemoteViews

RemoteViews翻译过来就是远程视图.顾名思义,RemoteViews不是当前进程的View,是属于SystemServer进程.应用程序与RemoteViews之间依赖Binder实现了进程间通信.

二、RemoteViews的用法

RemoteViews使用最多的场合是通知栏和桌面小插件. 以通知栏为例,讲解下它的用法.

1、新建一个Notification

这里要注意是在android3.0之前都是使用如下的形式构建一个Notification

        // 1.新建一个Notification对象         Notification mNotification = new Notification();         // 2.添加属性,比如标题、内容、优先级、图片等         mNotification.tickerText = "这是通知栏的标题";         mNotification.icon = R.drawable.ic_launcher;         mNotification.flags=Notification.FLAG_NO_CLEAR;         mNotification.setLatestEventInfo(this, "这是内容", "这是标题", null);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在3.0之后官方推荐使用建造者模式创建Notification.

Notification mNotification = new Notification.Builder(this)         .setContentTitle("这是标题 ")             .setContentText("这是内容")                 .setSmallIcon(R.drawable.ic_launcher)                         .build();
  • 1
  • 2
  • 3
  • 4
  • 5

Notification有很多属性,这里列举一些

 - setContentTitle       设置标题  - setContentText        设置内容  - setLargeIcon          设置通知栏大图标  - setSmallIcon          设置通知栏小图标  - setContent            设置RemoteViews  - setContentIntent      当通知条目被点击,就执行这个被设置的Intent.  - setDeleteIntent       当用户点击"Clear All Notifications"按钮区删除所有的通知的时候,这个被设置的Intent被执行  - setLights             设置闪光灯  - setSound              设置声音  - setPriority           设置优先级 

2、设置Notification的RemoteViews

如果要给通知栏使用自定义布局就要使用RemoteViews了,传入包名和相应的布局.

RemoteViews mRemoteViews=new RemoteViews("com.example.remoteviewdemo", R.layout.remoteview_layout);
  • 1

然后通过setContent()传入RemoteViews 对象即可.

这里顺便讲一下PendingIntent,PendingIntent是”延迟意图”的意思,就是当满足某一条件时出触发这个Intent.通过PendingIntent的getActivity、getBroadcast、getService等分别构建一个打开对应组件的延迟Intent. 
传入四个参数,context、intent、requestCode(自定义)、flag.

Intent intent=new Intent(MainActivity.this,MainActivity.class); PendingIntent mPendingIntent=PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • 1
  • 2

PendingIntent有4种flag.

 - FLAG_ONE_SHOT                只执行一次  - FLAG_NO_CREATE               若描述的Intent不存在则返回NULL值  - FLAG_CANCEL_CURRENT          如果描述的PendingIntent已经存在,则在产生新的Intent之前会先取消掉当前的  - FLAG_UPDATE_CURRENT          总是执行,这个flag用的最多 

3、获取通知管理者

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  • 1

4、弹出通知

调用notify方法,传入一个id(自定义)和通知实例即可.

manager.notify(1, mNotification);
  • 1

5、例子

我用一个按钮弹出通知,点击这个通知时进入到该Activity

public class MainActivity extends Activity {      private NotificationManager manager;     private Notification mNotification;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         //1.创建RemoteViews实例         RemoteViews mRemoteViews=new RemoteViews("com.example.remoteviewdemo", R.layout.remoteview_layout);          //2.构建一个打开Activity的PendingIntent         Intent intent=new Intent(MainActivity.this,MainActivity.class);         PendingIntent mPendingIntent=PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);          //3.创建一个Notification         mNotification = new Notification.Builder(this)         .setSmallIcon(R.drawable.ic_launcher)         .setContentIntent(mPendingIntent)         .setContent(mRemoteViews)         .build();          //4.获取NotificationManager         manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);          Button button1 = (Button) findViewById(R.id.button1);         button1.setOnClickListener(new OnClickListener() {              @Override             public void onClick(View v) {                 //弹出通知                 manager.notify(1, mNotification);             }         });      } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

如下图

6、改变RemoteViews的布局

RemoteViews并不能直接获得控件实例,然后对控件进行操作.它提供了 
setTextViewText(viewId, text)、setImageViewResource(viewId, srcId)等方法进行操作,传入控件id和相应的修改内容. 
列举一下常用的属性

 - setTextViewText(viewId, text)                     设置文本  - setTextColor(viewId, color)                       设置文本颜色  - setTextViewTextSize(viewId, units, size)          设置文本大小   - setImageViewBitmap(viewId, bitmap)                设置图片  - setImageViewResource(viewId, srcId)               根据图片资源设置图片  - setViewPadding(viewId, left, top, right, bottom)  设置Padding间距  - setOnClickPendingIntent(viewId, pendingIntent)    设置点击事件  

我这里就以setTextViewText改变文本的属性来讲解改变RemoteViews的原理. 
我在原来的代码上加上一个按钮点击改变内容

Button button2 = (Button) findViewById(R.id.button2); button2.setOnClickListener(new OnClickListener() {              @Override             public void onClick(View v) {                 mRemoteViews.setTextViewText(R.id.remote_content, "改变了内容");                 manager.notify(1, mNotification);             }         });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

看下效果

三、RemoteViews的改变原理

1.setTextViewText方法代码如下

public class RemoteViews implements Parcelable, Filter {     ...... public void setTextViewText(int viewId, CharSequence text) {         setCharSequence(viewId, "setText", text);     }     ......     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.调用了setCharSequence方法

public class RemoteViews implements Parcelable, Filter {     ...... public void setCharSequence(int viewId, String methodName, CharSequence value) {         addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));     }      ......     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3.在setCharSequence方法里调用了addAction方法,传入一个ReflectionAction实例,ReflectionAction继承自Action,它是用反射调用的

private final class ReflectionAction extends Action {     ......     ReflectionAction(int viewId, String methodName, int type, Object value) {             this.viewId = viewId;             this.methodName = methodName;             this.type = type;             this.value = value;         }    ......    }     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.看下addAction方法,用了一个集合来保存Action实例,然后更新已使用内存的统计情况

public class RemoteViews implements Parcelable, Filter {     ...... private void addAction(Action a) {          if (mActions == null) {             mActions = new ArrayList<Action>();         }         //添加Action         mActions.add(a);          // 更新已使用内存的统计情况         a.updateMemoryUsageEstimate(mMemoryUsageCounter);     }     ......    }   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这一步之后,会调用

manager.notify(1, mNotification);
  • 1

来更新,追踪这个notify方法.

public class NotificationManager {     ...... public void notify(String tag, int id, Notification notification)     {          ......          INotificationManager service = getService();          try {             service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,                     stripped, idOut, UserHandle.myUserId());          ......                 }     ......     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

5.上面会调用getService方法返回INotificationManager这个系统服务,它是在SystemServer进程添加的.然后该服务调用 enqueueNotificationWithTag方法最后层层调用到

public class NotificationManagerService extends INotificationManager.Stub {     ...... StatusBarNotification n = new StatusBarNotification(pkg, id, tag, r.uid, r.initialPid, notification); try {                      mStatusBar.updateNotification(r.statusBarKey, n)      }     ......     } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

新建了StatusBarNotification实例,然后调用updateNotification方法. 
这个方法会进入到

public class PhoneStatusBar extends StatusBar {     ...... public void updateNotification(IBinder key, StatusBarNotification notification) {     ......      final RemoteViews contentView = notification.notification.contentView;     ......     contentView.reapply(mContext, oldEntry.content);     ......     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

会调用StatusBarNotification 的notification.contentView返回RemoteViews 对象,然后调用reapply方法.

6.回到RemoteViews 的reapply方法

public class RemoteViews implements Parcelable, Filter {     ...... public void reapply(Context context, View v, OnClickHandler handler) {   RemoteViews rvToApply = getRemoteViewsToApply(context);  ......  rvToApply.performApply(v, (ViewGroup) v.getParent(), handler);      }  private void performApply(View v, ViewGroup parent, OnClickHandler handler) {         if (mActions != null) {             handler = handler == null ? DEFAULT_ON_CLICK_HANDLER : handler;             final int count = mActions.size();             for (int i = 0; i < count; i++) {                 Action a = mActions.get(i);                 //调用apply方法                 a.apply(v, parent, handler);             }         }     }       ......     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

最终调用apply方法,在这里加载新的布局,RemoteViews就是这么完成的.

public class RemoteViews implements Parcelable, Filter {     ...... public View apply(Context context, ViewGroup parent, OnClickHandler handler) { RemoteViews rvToApply = getRemoteViewsToApply(context);         View result; LayoutInflater inflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);         ......         //加载布局         result = inflater.inflate(rvToApply.getLayoutId(), parent, false);          rvToApply.performApply(result, parent, handler);          return result;     }      ......     }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

总结

RemoteViews运行在SystemServer进程,更新RemoteViews要通过Binder获取到对应的服务然后调用RemoteViews内部的apply方法加载更新布局.

完全理解Android中的RemoteViews的更多相关文章

  1. 【转】Android菜单详解——理解android中的Menu--不错

    原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...

  2. 深入理解Android中View

    文章目录   [隐藏] 一.View是什么? 二.View创建的一个概述: 三.View的标志(Flag)系统 四.MeasureSpec 五.几个重要方法简介 5.1 onFinishInflate ...

  3. Android菜单详解(一)——理解android中的Menu

    前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至 ...

  4. 深入理解Android中ViewGroup

    文章目录   [隐藏] 一.ViewGroup是什么? 二.ViewGroup这个容器 2.1 添加View的算法 2.1.1 我们先来分析addViewInner方法: 2.1.2 addInArr ...

  5. 彻底理解 Android 中的阴影

    如果我们想创造更好的 Android App,我相信我们需要遵循 Material Design 的设计规范.一般而言,Material Design 是一个包含光线,材质和投影的三维环境.如果我们想 ...

  6. 理解android中ListFragment和Loader

    一直以来不知Android中Loader怎么用,今天晚上特意花了时间来研究,算是基本上搞明白了,现在把相关的注释和代码发出来,以便笔记和给网友一个参考,错误之处还望大家给我留言,共同进步,这个例子采用 ...

  7. 一个demo让你彻底理解Android中触摸事件的分发

    注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOW ...

  8. 绝对让你理解Android中的Context

    这个问题是StackOverFlow上面一个热门的问题What is Context in Android? 整理这篇文章的目的是Context确实是一个非常抽象的东西.我们在项目中随手都会用到它,但 ...

  9. 理解Android中的注解与反射

    反射 Java反射(Reflection)定义 Java反射机制是指在运行状态中 对于任意一个类,都能知道这个类的所有属性和方法:对于任何一个对象,都能够调用它的任何一个方法和属性: 这样动态获取新的 ...

随机推荐

  1. server.xml文件详解

    一.server.xml文件介绍 1.server.xml作用     Server.xml配置文件用于对整个容器进行相关的配置. 2.server.xml文件的配置元素列表 <Server&g ...

  2. ZOJ 3331 Process the Tasks(双塔DP)

    Process the Tasks Time Limit: 1 Second      Memory Limit: 32768 KB There are two machines A and B. T ...

  3. java 常用的几个配置

    1.保存代码格式化,打勾即可 2.如何让eclipse像vs那样自动提示,在打勾的地方加入 abcdefghijklmnopqrstuvwxyz.即可

  4. Response 和 Request

    1. request 对象和 response 对象均由服务器创建. 2. 服务器处理请求的流程: 服务器每次收到请求时, 都会为这个请求开辟一个新的线程; 服务器会把客户端的请求数据封装到 requ ...

  5. 如何重定向 stderr ?

    可以使用该方法写一个轻量级日志类 #include <cstdio> int main() { FILE *stream = freopen("freopen.txt" ...

  6. win7查看某个端口被占用的解决方法

    1.开始---->运行---->cmd,或者是window+R组合键,调出命令窗口. 2.输入命令:netstat -ano,列出所有端口的情况.在列表中我们观察被占用的端口,比如是491 ...

  7. centos7在vmware上无法上网

    centos7在虚拟机中设置NAT后也无法上网! 首先激活网卡!打开桌面右键在终端中打开:cd /etc/sysconfig/network-scripts/ls 找到以ifcfg开头的,如ifcfg ...

  8. .net ASPxTreeList 使用手记

    ASPxTreeList在使用ASPxGridViewExporter控件做导出时,如果指定文件名是中文时会乱码可以用以下方法解决: grvExporter为ASPxGridViewExporter控 ...

  9. struts 多文件上传 annotation注解(零配置)+ ajaxfileupload + 异步 版本

    [本文简介] struts 多文件上传.基于”零配置“+"ajaxfileupload" 的一个简单例子. [导入依赖jar包] jquery-1.7.2.js : http:// ...

  10. Linux学习笔记(11)linux网络管理与配置之一——配置路由与默认网关,双网卡绑定(5-6)

    Linux学习笔记(11)linux网络管理与配置之一——配置路由与默认网关,双网卡绑定(5-6) 大纲目录 0.常用linux基础网络命令 1.配置主机名 2.配置网卡信息与IP地址 3.配置DNS ...