RemoteViews,顾名思义,就是远程的View,也就是可以运行在其他进程中的View。RemoteViews常用在通知和桌面小组件中。

一、RemoteViews应用到通知

  首先来介绍一下系统自带的通知(Notification)的使用。Notification的使用有两种方法,分别是Notification直接创建的方式和使用Notification.Builder创建者模式创建的方式。

  先来看一下使用Notification直接创建的方式的代码:

Notification notification = new Notification();
notification.icon = R.mipmap.ic_launcher; // 小图标
notification.largeIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round); // 大图标
notification.defaults = Notification.DEFAULT_ALL; // 设置默认的提示音、振动方式、灯光等
notification.category = "Category";
notification.when = System.currentTimeMillis(); // 设置通知发送的时间戳
notification.tickerText = "Ticker Text"; // 设置通知首次弹出时,状态栏上显示的文本
notification.flags = Notification.FLAG_AUTO_CANCEL; // 点击通知后通知在通知栏上消失
notification.contentIntent = PendingIntent.getActivity(MainActivity.this, 0x001,
new Intent(MainActivity.this, TargetActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); // 设置通知的点击事件
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(1, notification); // 发送系统通知

  通过上面的代码,就可以简单地发送一条通知到通知栏中。使用这种方式不需要有API版本的限制,但可以进行的操作比较少。

  下面来看一下使用Notification.Builder创建者模式创建通知的代码:

PendingIntent pi = PendingIntent.getActivity(MainActivity.this, 0x001,
new Intent(MainActivity.this, TargetActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder nb = new Notification.Builder(MainActivity.this)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round)) // 大图标
.setSmallIcon(R.mipmap.ic_launcher) // 小图标
.setContentText("Content Text") // 内容
.setSubText("Sub Text") // 在通知中,APP名称的副标题
.setContentTitle("Content Title") // 标题
.setTicker("Ticker") // 设置通知首次弹出时,状态栏上显示的文本
.setWhen(System.currentTimeMillis()) // 设置通知发送的时间戳
.setAutoCancel(true) // 点击通知后通知在通知栏上消失
.setDefaults(Notification.DEFAULT_ALL) // 设置默认的提示音、振动方式、灯光等
.setContentIntent(pi); // 设置通知的点击事件
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(1, nb.build()); // build()方法需要的最低API为16

  使用这种方式,需要注意对项目的API版本进行一定的控制,上面这段代码需要的API版本最低是16。

  上面两种方式都是发送系统自带的通知。如果我们需要自定义通知的样式,就需要使用到 RemoteViews 了。RemoteViews给我们提供了一种可以在其他进程中生成View并进行更新的机制,但是它可以控制和操作的View有一定的限制,具体如下:

Layout:
FrameLayout、LinearLayout、RelativeLayout、GridLayout
View:
AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewStub

  使用RemoteViews发送一个自定义系统通知的代码如下:

PendingIntent pi = PendingIntent.getActivity(MainActivity.this, 0x001,
new Intent(MainActivity.this, TargetActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews remoteView = new RemoteViews(getPackageName(), R.layout.remoteview_main);
remoteView.setTextViewText(R.id.remoteview_main_title, "Title");
remoteView.setTextViewText(R.id.remoteview_main_content, "ContentContentContent");
remoteView.setImageViewResource(R.id.remoteview_main_icon, R.mipmap.ic_launcher_round);
remoteView.setOnClickPendingIntent(R.id.remoteview_main_view, pi);
Notification.Builder nb = new Notification.Builder(MainActivity.this)
.setSmallIcon(R.mipmap.ic_launcher) // 小图标
.setCustomContentView(remoteView) // 设置自定义的RemoteView,需要API最低为24
.setWhen(System.currentTimeMillis()) // 设置通知发送的时间戳
.setAutoCancel(true) // 点击通知后通知在通知栏上消失
.setDefaults(Notification.DEFAULT_ALL); // 设置默认的提示音、振动方式、灯光等
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(1, nb.build()); // build()方法需要的最低API为16

  可以看到,我们在自定义的通知布局中设置了TextView和ImageView,并在代码中动态地更新了其显示的内容。

二、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="8640000"> </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();
}
}, 0, 1000);
} @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进程中进行具体的更新操作。

【Android - 进阶】之RemoteViews简介的更多相关文章

  1. 我的Android进阶之旅------>经典的大牛博客推荐(排名不分先后)!!

    本文来自:http://blog.csdn.net/ouyang_peng/article/details/11358405 今天看到一篇文章,收藏了很多大牛的博客,在这里分享一下 谦虚的天下 柳志超 ...

  2. Android进阶之路(1)-详解MVC

    最近因为换工作的原因没有写博客,现在慢慢稳定了,我准备写一些关于Android 进阶的文章,也是为了督促自己学习,大家一起进步! 今天详细的分析一下Android APP架构之一:MVC ### MV ...

  3. Android进阶之路(2)-详解MVP

    ### MVP简介 >MVP 全称:Model-View-Presenter :MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的[地方](https://baike.baidu.co ...

  4. Android 进阶 Android 中的 IOC 框架 【ViewInject】 (下)

    上一篇博客我们已经带大家简单的吹了一下IoC,实现了Activity中View的布局以及控件的注入,如果你不了解,请参考:Android 进阶 教你打造 Android 中的 IOC 框架 [View ...

  5. 【Android进阶系列教程】前言

    起因 因为初学Android的时候还没有写博客的意识,现在Android的门是入了,正在进阶的道路上行走,但是就这一路也走了不少的弯路.我想,总得来说Android入门还是比较容易的,网络资源比较丰富 ...

  6. Android开发面试经——4.常见Android进阶笔试题(更新中...)

      Android开发(29)  版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http:/ ...

  7. 【转】Android 防破解技术简介

    http://www.cnblogs.com/likeandroid/p/4888808.html Android 防破解技术简介 这几年随着互联网的不断发展,Android App 也越来越多!但是 ...

  8. [置顶] 我的Android进阶之旅------>介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam

    由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程 ...

  9. 《Android进阶》之第七篇 NDK的使用

    <Android进阶>之第一篇 在Java中调用C库函数 这一篇列举的方法是在NDK没有出来时候用的方式 在Android发布NDK之后,可以这样使用 一.首先下载android-ndk ...

  10. 我的Android进阶之旅------&gt; Android在TextView中显示图片方法

    面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包括图像的文本信息).并简要说明实现方法. 答案:Android SDK支持例如以下显示富文本信息的方式. 1.使用T ...

随机推荐

  1. 面向云原生的混沌工程工具-ChaosBlade

    作者 | 肖长军(穹谷)阿里云智能事业群技术专家   导读:随着云原生系统的演进,如何保障系统的稳定性受到很大的挑战,混沌工程通过反脆弱思想,对系统注入故障,提前发现系统问题,提升系统的容错能力.Ch ...

  2. Linux 命令之 crontab

    crontab 简介 crontab 主要用于需要管理周期执行定时任务的场景 crontab 安装 (有些系统默认已经带了 crontab,无需安装的朋友可以直接跳过本节) 安装: yum insta ...

  3. USACO 07DEC 道路建设(Building Roads)

    Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he ...

  4. 关于路由器漏洞利用,qemu环境搭建,网络配置的总结

    FAT 搭建的坑 1 先按照官方步骤进行,完成后进行如下步骤 2 修改 move /firmadyne into /firmware-analysis-toolkit navigate to the ...

  5. NOIP模拟 1

    NOIP模拟1,到现在时间已经比较长了.. 那天是6.14,今天7.18了 //然鹅我看着最前边缺失的模拟1,还是终于忍不住把它补上,为了保持顺序2345重新发布了一遍.. #   用  户  名   ...

  6. Python3获取豆瓣图书标签的前20本热门书籍(一)

    介绍 第一篇主要获取豆瓣的大分类.大分类下的具体分类以及具体分类下的前20本热门书籍,第二篇对获取的数据进行分析. 准备 Python3.6.requests.BeautifulSoup4 演示 代码 ...

  7. 使用Typescript重构axios(八)——实现基础功能:处理响应data

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  8. 问题 A: 雷神领域

    传送门 题目描述 L君,S大陆首屈一指的天才魔法师,创造了一个新魔法:雷神领域.  这个魔法会首先在地面上形成正方网格魔法阵列,然后在某些位置召唤雷电轴标.注意:一个位置只能有一个雷电轴标存在. 雷电 ...

  9. 简单搭建syslog-ng server记录log

    ### 简单搭建syslog-ng server记录log 安装syslog-ng apt-get install syslog-ng 安装syslog-ng 配置syslog-ng vim /etc ...

  10. SVN--服务端安装和设置---centos7

    一.安装环境 [root@localhost ~]# getenforce Disabled [root@localhost ~]# systemctl disable firewalld 二.yum ...