需求是这样的:一个显示应用下载器状态的通知栏,能显示下载进度,下载速度,任务数量等等信息。
1. 常驻通知栏
其实出来这个需求是因为下载器需要一个Service作为承载,特别是当应用切换到后台时,没有一个前台Service在跑的话,很容易被系统回收掉。一开始年少无知,不知道为啥应用宝,豌豆荚等等应用商店的下载都要启动一个常驻的通知栏,后来才发现这样才能将Service保持在前台运行。
常驻通知栏需要设置如下几个属性:
mNotificationBuilder = new NotificationCompat.Builder(this.getApplication());
mNotificationBuilder.setAutoCancel(false); //点击不消失
mNotificationBuilder.setOngoing(true); // 不能滑动清除
并且在改变通知栏信息的时候用
this.startForeground(NOTIFACTION_ID, mNotificationBuilder.build());
而不是
mNotificationManager.notify(NOTIFACTION_ID, mNotificationBuilder.build());
startForeground是service的一个方法,能将service声明为前台service防止被清除
2.控制Service的生命周期
在使用过程中发现直接通过显示的发送startService和stopService并不能准确的控制service的生命周期,特别是有可能连续的调用stopService和startService导致start和stop不能顺序执行,经常导致停止没法正常调用,因此通过在service内部建立静态公开方法来控制,代码如下:
public static void stopService(Context context) {
Intent intent = new Intent(context, DownloadService.class);
intent.putExtra(IntentKey.DOWNLOAD_NOTIFICATION_IS_BORN, false);
try {
context.startService(intent);
} catch (Exception e) {
}
}
public static void startService(Context context, String taskId) {
Intent intent = new Intent(context, DownloadService.class);
intent.putExtra(IntentKey.DOWNLOAD_NOTIFICATION_IS_BORN, true);
try {
context.startService(intent);
} catch (Exception e) {
}
}
然后在Service的onStartCommand中进行判断
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
boolean isBorn;
try {
isBorn =intent.getBooleanExtra(IntentKey.DOWNLOAD_NOTIFICATION_IS_BORN, true);
} catch (RuntimeException e) {
e.printStackTrace();
isBorn = false;
}
if (!isBorn) {
LogTool.i(TAG, "stopService");
stopForeground(true);
try {
stopSelf();
} catch (Exception e) {
LogTool.w(TAG, e);
}
mNotificationManager.cancel(NOTIFACTION_ID);
} else {
LogTool.i(TAG, "startService");
initNotification();
}
}
return START_NOT_STICKY;
}
实践证明,这样的控制方法比较靠谱
3.定义通知栏样式
由于谷歌提供的几种基本样式不能满足需求,只能通过RemoteView来自定义通知栏,代码如下:
mRemoteView = new RemoteViews(this.getPackageName(), R.layout.custom_notification);
mNotificationBuilder.setContent(mRemoteView);
要注意,对于RemoteView只能通过其提供的特定方法来改变界面布局。
4.自定义图标的一些坑
一开始直接使用应用图标作为常驻通知栏的小图标,发现会在大部分的机子出现弹出Ticker的时候图标异常的大,甚至在5.0以上的机子上出现一篇白色的情况,查阅文档发现谷歌建议在5.0以上的通知栏常驻图标采用纯白和全透明两种颜色来设计图标,以期达到统一的视觉效果,当然,如果不想折腾,可以直接将编译的版本设置成target 22一下就可以了。
坑当然不止这些,让设计弄了一套白色的和透明的通知栏图标之后,发现在展示ticker的时候仍然会出现异常大的图标,应该是尺寸不适合的原因,看来不能和应用图标一样的规格。Google发现一个网站,可以自动生成一套通知栏图标,地址如下:
生成一套通知栏图标的网站
可以发现为了兼容3.0以下会有两套图标生成,一套是透明底,白色图,一套是透明底,灰色图。具体效果可以自己试验,不过注意,原图必须要符合官方的设计,即只能有两种颜色,白色和透明色。
5.总结
Notification还有一些比较高级的方法没有研究,但是上面所有的已经可以满足需求,以后有什么新的需求再去继续研究吧。