emoteViews,顾名思义,就是远程的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,
newIntent(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,
newIntent(MainActivity.this, TargetActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder nb =newNotification.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,
newIntent(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 =newNotification.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在桌面小组件中的应用。在这个例子中,我们向系统中添加一个小组件,在这个小组件中显示当前的日期和时间。
首先,设置桌面小组件的布局,具体代码如下:
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"/>
然后,编写桌面小组件的配置文件,具体步骤是:在项目res文件夹下新建一个xml文件夹,在xml文件夹中创建一个XML文件,具体代码如下:
这个文件中的各个参数的解释如下:
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;
privateSimpleDateFormat formatter =newSimpleDateFormat("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 =newComponentName(getApplicationContext(), WidgetProvider.class);
manager.updateAppWidget(componentName, remoteView);
}
@Override
publicvoid 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(newIntent(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(newIntent(context, TimerService.class));
}
}
最后,在Manifest文件中配置刚刚编写的Service和BroadcastReceiver(AppWidgetProvider相当于一个广播),代码如下:
android:name="android.appwidget.provider" android:resource="@xml/widget"/>
这里需要注意,
编写完上述代码之后,运行结果如下图所示: