remoteViews简介
RemoteViews从字面上看是一种远程视图。RemoteViews具有View的结构,既然是远程View,那么它就可以在其他进程中显示。由于它可以跨进程显示,所以为了能够更新他的界面,RemoteViews提供一组基础的操作用于跨进程更新它的UI。
RemoteViews在Android日常开发中最常见的使用场景有两种:通知栏的通知和桌面小部件。通知栏通知大家应该都不陌生,因为这还经常用到的,notification主要是通过NotificationManager的notify方法来实现,它除了默认的效果外,开发人员还可以根据自己的需求自定义UI布局。桌面小部件是通过AppWidgetProvider来实现的,其实AppWidgetProvider是一个广播。通知栏通知和小部件的开发过程中经常会用到RemoteViews。它们在更新UI的时候无法像Activity和Fragment那样直接更新,前面讲过,因为它是跨进程的view,更确切一点来说的话,它是运行在SystemServer进程中。为了能够跨进程更新界面,RemoteViews提供了一些列可以跨进程更新UI的方法,内部有一些列的set方法,这些方法都是View的子集。
一、RemoteViews自定义Notification通知栏
public class MainActivity extends Activity implements View.OnClickListener { private Button btn_one,btn_two,btn_three,btn_four;
private NotificationManager manager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_one = (Button) findViewById(R.id.btn_one);
btn_one.setOnClickListener(this);
btn_two = (Button) findViewById(R.id.btn_two);
btn_two.setOnClickListener(this);
btn_three = (Button) findViewById(R.id.btn_three);
btn_three.setOnClickListener(this);
btn_four = (Button) findViewById(R.id.btn_four);
btn_four.setOnClickListener(this);
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
} @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_one://默认通知
PendingIntent pendingIntent1=PendingIntent.getActivity(this,,new Intent(this,OtherActivity.class),PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification1=new Notification();
notification1.icon=R.drawable.head;
notification1.when=System.currentTimeMillis();
notification1.tickerText="您有新短消息,请注意查收!";
notification1.contentIntent=pendingIntent1;
manager.notify(,notification1); break;
case R.id.btn_two://API11之后使用
PendingIntent pendingIntent2=PendingIntent.getActivity(this,,new Intent(this,OtherActivity.class),PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification2=new Notification.Builder(this)
.setSmallIcon(R.drawable.head)//即便自定义了图标,但有时候还是显示系统默认的,应该与手机类型有关
.setContentTitle("好消息")
.setContentText("API11之后的通知")
.setTicker("hello world")
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent2)
.setNumber() //在最右侧现实。这个number起到一个序列号的作用,如果多个触发多个通知(同一ID),可以指定显示哪一个。
.getNotification(); //build()是在API16及之后增加的,在API11中可以使用getNotificatin()来代替
manager.notify(,notification2);
break;
case R.id.btn_three://API16之后使用
PendingIntent pendingIntent3=PendingIntent.getActivity(this,,new Intent(this,OtherActivity.class),PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification3=new Notification.Builder(this)
.setSmallIcon(R.drawable.head)
.setContentTitle("好消息")
.setContentText("API16之后的通知")
.setTicker("hello world")
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent3)
.setNumber()
.build();
manager.notify(,notification3);
break;
case R.id.btn_four://自定义通知,
Notification notification = new Notification();
notification.when = System.currentTimeMillis();
notification.flags = Notification.FLAG_AUTO_CANCEL;
notification.tickerText = "hello world";
notification.icon = R.drawable.head;//这是个坑,如果不设置icon,通知不显示 Intent intent = new Intent(MainActivity.this, OtherActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, , intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.remote_layout);
remoteViews.setTextViewText(R.id.tv_title, "请假条");
remoteViews.setTextViewText(R.id.tv_content, "世界这么大,我想去看看");
remoteViews.setImageViewResource(R.id.iv_head, R.drawable.head); notification.contentIntent = pendingIntent;
notification.contentView = remoteViews;
manager.notify(, notification);
break;
}
}
}
通知栏的布局remote_layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal"> <ImageView
android:id="@+id/iv_head"
android:layout_width="40dp"
android:layout_height="40dp" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:orientation="vertical"> <TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题" /> <TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="3dp"
android:text="内容。。。。" />
</LinearLayout>
</LinearLayout>
二、RemoteViews应用到桌面小组件
RemoteViews也可以应用到桌面小组件中。这里我们通过一个例子来了解RemoteViews应用到桌面小组件的步骤,它总共分为五步,分别是:设置桌面小组件的布局、编写桌面小组件的配置文件、编写桌面小组件更新的Service、编写桌面小组件的控制类AppWidgetProvider、配置配置文件。
我们通过下面这个例子来介绍RemoteViews在桌面小组件中的应用。在这个例子中,我们向系统中添加一个小组件,在这个小组件中显示当前的日期和时间。
首先,设置桌面小组件的布局,具体代码如下:
<?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"> <TextView
android:id="@+id/widget_main_tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="22.0sp"
android:textStyle="bold" /> </LinearLayout>
然后,编写桌面小组件的配置文件,具体步骤是:在项目res文件夹下新建一个xml文件夹,在xml文件夹中创建一个XML文件,具体代码如下:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_main"
android:minHeight="100.0dip"
android:minWidth="150.0dip"
android:updatePeriodMillis=""> </appwidget-provider>
这个文件中的各个参数的解释如下:
initialLayout:桌面小组件的布局XML文件
minHeight:桌面小组件的最小显示高度
minWidth:桌面小组件的最小显示宽度
updatePeriodMillis:桌面小组件的更新周期。这个周期最短是30分钟
然后,编写一个Service,在这个Service中动态地获取到当前的时间并更新到桌面小组件中,代码如下:
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.widget.RemoteViews; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; /**
* 定时器Service
*/
public class TimerService extends Service {
private Timer timer;
private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); @Override
public void onCreate() {
super.onCreate();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
updateViews();
}
}, , );
} @Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
} private void updateViews() {
String time = formatter.format(new Date());
RemoteViews remoteView = new RemoteViews(getPackageName(), R.layout.widget_main);
remoteView.setTextViewText(R.id.widget_main_tv_time, time);
AppWidgetManager manager = AppWidgetManager.getInstance(getApplicationContext());
ComponentName componentName = new ComponentName(getApplicationContext(), WidgetProvider.class);
manager.updateAppWidget(componentName, remoteView);
} @Override
public void onDestroy() {
super.onDestroy();
timer = null;
}
}
然后,编写一个类继承自AppWidgetProvier,用来统一管理项目中的小组件,代码如下:
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent; /**
* AppWidgetProvider的子类,相当于一个广播
*/
public class WidgetProvider extends AppWidgetProvider {
/**
* 当小组件被添加到屏幕上时回调
*/
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
context.startService(new Intent(context, TimerService.class));
} /**
* 当小组件被刷新时回调
*/
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
/**
* 当widget小组件从屏幕移除时回调
*/
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
} /**
* 当最后一个小组件被从屏幕中移除时回调
*/
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
context.stopService(new Intent(context, TimerService.class));
}
}
最后,在Manifest文件中配置刚刚编写的Service和BroadcastReceiver(AppWidgetProvider相当于一个广播),代码如下:
<service android:name=".TimerService" />
<receiver android:name=".WidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget" />
</receiver>
这里需要注意,<intent-filter>标签中的action的name和<meta-data>标签中的name的值是固定的,reousrce代表的是第二步中配置文件的位置。
编写完上述代码之后,运行结果如下图所示:
三、RemoteViews原理
我们的通知和桌面小组件分别是由NotificationManager和AppWidgetManager管理的,而NotificationManager和AppWidgetManager又通过Binder分别和SystemServer进程中的NotificationManagerServer和AppWidgetService进行通信,这就构成了跨进程通信的场景。
RemoteViews实现了Parcelable接口,因此它可以在进程间进行传输。
首先,RemoteViews通过Binder传递到SystemServer进程中,系统会根据RemoteViews提供的包名等信息,去项目包中找到RemoteViews显示的布局等资源,然后通过LayoutInflator去加载RemoteViews中的布局文件,接着,系统会对RemoteViews进行一系列的更新操作,这些操作都是通过RemoteViews对象的set方法进行的,这些更新操作并不是立即执行的,而是在RemoteViews被加载完成之后才执行的,具体流程是:我们调用了set方法后,通过NotificationManager和AppWidgetManager来提交更新任务,然后在SystemServer进程中进行具体的更新操作。
remoteViews简介的更多相关文章
- 【Android - 进阶】之RemoteViews简介
RemoteViews,顾名思义,就是远程的View,也就是可以运行在其他进程中的View.RemoteViews常用在通知和桌面小组件中. 一.RemoteViews应用到通知 首先来介绍一下系统自 ...
- ANDROID_MARS学习笔记_S02_006_APPWIDGET2_PendingIntent及RemoteViews实现widget绑定点击事件
一.代码流程 1.ExampleAppWidgetProvider的onUpdate(Context context, AppWidgetManager appWidgetManager, int[] ...
- RemoteViews的理解和使用
一.RemoteViews简介 作用:跨进程更新界面 使用场景:通知栏.桌面小部件 二.在通知栏上的应用 原理:通过RemoteViews加载布局,通过 ...
- ASP.NET Core 1.1 简介
ASP.NET Core 1.1 于2016年11月16日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强.这个版本包含了多个新的中间件组件.针对Windows的WebListener服 ...
- MVVM模式和在WPF中的实现(一)MVVM模式简介
MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...
- Cassandra简介
在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...
- REST简介
一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式.”但是在要求详细讲述它所提出的各个约束,以及如何开始搭建REST服务时,却很少有人能够清晰地说出它到底是什么,需要遵守什么样的准则. ...
- Microservice架构模式简介
在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...
- const,static,extern 简介
const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...
随机推荐
- Java8函数式接口以及lambda表达式实践
罗列一下遇到可以转换成lamada表达式的场景,仅供参考,如有更好的方式,欢迎在评论区留言. 1.计算订单总金额 订单总金额一般是在后台循环叠加每个购买商品的金额已获取到,通常的方式如下 BigDec ...
- solrCloud设置Tomcat jvm内存解决内存溢出的问题
几乎已经搜遍了整个网络,没有找到一篇解决设置solr在Tomcat下设置虚拟机内存的文章. 因为之前一直是在Tomcat中设置zkhost参数,在加上jvm参数后会无法启动,添加其他参数也没有生效 ...
- 使用三种方法求解前N个正整数的排列
本篇博文给大家介绍前N个正整数的排列求解的三种方式.第一种是暴力求解法:第二种则另外声明了一个长度为N的数组,并且将已经排列过的数字保存其中:第三种方式则采用了另外一种思路,即首先获取N个整数的升序排 ...
- JSP和Servlet笔记
一.JSP的3个编译指令 作用:page指令用于设置整个jsp页面相关的属性,比如页面的编码格式.所包含的文件等等,它们包含在<%@ page %>标记中. 1)page 指令 以 ...
- 记录因webpack版本问题导致vue-cli快速搭建的项目运行时报错!
今日突然在群里见到好几个小伙伴说在创建vue项目后不能跑,会报错. 刚开始还不信,花了几分钟时间自己试了下,还真报错了!如下图 小伙伴的报错,如下图! 百思不得其解,看了运行的日志也找不出原因.于 ...
- Jfinal控制器源码解读
本文对Jfinal的控制器源码做以下分析. PS:控制器是所有请求跳转的基础,本文就Jfinal控制器的继承关系及初始化的方法做出解释说明. 啰嗦下:所有的请求和响应都是都是通过web容器封装,我们主 ...
- reduce 方法 (Array) (JavaScript)
对数组中的所有元素调用指定的回调函数.该回调函数的返回值为累积结果,并且此返回值在下一次调用该回调函数时作为参数提供. 语法 array1.reduce(callbackfn[, in ...
- Codeforces 768A Oath of the Night's Watch
A. Oath of the Night's Watch time limit per test:2 seconds memory limit per test:256 megabytes input ...
- isdigit函数
isdigit是计算机应用C语言中的一个函数,主要用于检查参数c是否为阿拉伯数字0到9. 相关函数 isdigit 表头文件 #include <ctype.h>(C语言),#includ ...
- SPI、I2C、UART(转)
UART与USART(转) UART需要固定的波特率,就是说两位数据的间隔要相等. UART总线是异步串口,一般由波特率产生器(产生的波特率等于传输波特率的16倍).UART接收器.UART发送器组成 ...