Android的Notification是android系统中很重要的一个机制,产品人员常常利用通知栏的方式,跟用户进行弱沟通。拥有推送通知的app要比没有此类功能的app活跃率要高很多。另外类似于墨迹天气,清理大师等app,也会将通知栏常驻,利用自定义的布局,方便用户及时快捷的查看所需的信息和使用快捷的功能。所以Notification的使用,也在开发当中,使用的越来越频繁。今天我就来跟大家分享一下Notification的常用事项。
我不了解大家平时怎么使用Notification,我常常看到有些人的代码是这样写的:
- Notification notification=new Notification(notificationIcon, notificationTitle, when);
- notification.defaults=Notification.DEFAULT_ALL;
- Intent intent=new Intent(MainActivity.this,SecondActivity.class);
- PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this, 0, intent, 0);
- notification.setLatestEventInfo(this,"测试展开title", "测试展开内容",pendingIntent);
- 。。。。。。。。。。。。。
具体的代码我就不贴全了,因为大家如果注意IDE的提示的话,就会发现,其实这是一种不推荐的用法,API的支持已经过时了。最新的Notification的用法,是推荐使用V4包下的NotificationCompat.Builder,利用它,进行各种设置,具体的用法先别着急,我们慢慢道来。
- NotificationCompat.Builder notifyBuilder = new NotificationCompat.Builder(
- this);
图示中的序号1,叫做Content title,通过这个方法来设置:
- notifyBuilder.setContentTitle("This is My Notification");
图示中的序号3,叫做Content text,利用下面的方法来设置:
- notifyBuilder.setContentText("Hello World");
- notifyBuilder.setSmallIcon(R.drawable.small);
- // 如果不设置LargeIcon,那么系统会默认将上面的SmallIcon显示在通知选项的最左侧,右下角的小图标将不再显示
- Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bigicon);
- notifyBuilder.setLargeIcon(bitmap);
- // 这里用来显示右下角的数字
- notifyBuilder.setNumber(10);
- notifyBuilder.setWhen(System.currentTimeMillis());
以上就是关于Notification的基本设置,下面,我们继续看看其它方面的设置,直接上代码:
- // 将AutoCancel设为true后,当你点击通知栏的notification后,它会自动被取消消失
- notifyBuilder.setAutoCancel(true);
- // 将Ongoing设为true 那么notification将不能滑动删除
- // notifyBuilder.setOngoing(true);
- // 从Android4.1开始,可以通过以下方法,设置notification的优先级,优先级越高的,通知排的越靠前,优先级低的,不会在手机最顶部的状态栏显示图标
- notifyBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
- // notifyBuilder.setPriority(NotificationCompat.PRIORITY_MIN);
- notifyBuilder.setTicker("Hi,Notification is here");
- // Uri uri =
- // Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.cat);
- // Uri uri = Uri.parse("file:///mnt/sdcard/cat.mp3");
- // notifyBuilder.setSound(uri);
- // Notification.DEFAULT_ALL:铃声、闪光、震动均系统默认。
- // Notification.DEFAULT_SOUND:系统默认铃声。
- // Notification.DEFAULT_VIBRATE:系统默认震动。
- // Notification.DEFAULT_LIGHTS:系统默认闪光。
- // notifyBuilder.setDefaults(Notification.DEFAULT_ALL);
- NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- mNotificationManager.notify(NOTIFY_ID, notifyBuilder.build());
说了这么多,还有最重要的一点没有讲,那就是在你设置完notification的各种属性后,你需要启动这个notification,否则就前功尽弃了,启动的方法,如上面的示例代码所示,你需要先获取一个NotificationManager的实例,然后调用notify的方法,notifyBuilder.build()这个方法,可以实例化一个notification的实例,另外,你还需要为这个notification分配一个独一无二的的id号,将来notification的更新和删除,都是依靠这个id号来做索引对应的。
有时候,我们会涉及到这么一个需求,那就是,产品设计,希望我们能够监听notification的销毁,意思就是说,当用户手动滑动通知将其删除或者通过手机的删除按钮将其清空时,我们希望可以捕获到这一信息,并作出相应的处理。比如说,我们在通知栏发送了一个通知,用来更新一个资源的下载进度,当用户删除这个通知后,我们希望可以监听到这一变化,作出相应的处理,比如取消下载,比如重新下载等等,那么,应该如何监听取消的行为呢?请看代码:
- Intent deleteIntent = new Intent(this, DeleteService.class);
- int deleteCode = (int) SystemClock.uptimeMillis();
- PendingIntent deletePendingIntent = PendingIntent.getService(this,
- deleteCode, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- notifyBuilder.setDeleteIntent(deletePendingIntent);
上面的内容,我们大概了解了如何给notification设定显示的内容,和如何监听销毁的行为。但是常常,我们会发现,除了以上功能外,我们经常遇见的情形时,当我们点击了一个notification后,就会自动打开一个页面,展示出信息来源的具体页面,接下来,我们就针对这种情况,来看看代码是如何控制的。
刚刚提到的自动跳转页面的功能,看似很简单的一个逻辑,其实也包含了各种逻辑处理情况,其中最主要的是有两种:
一:当我们处在手机桌面主屏的时候,突然来了一条邮箱的信息,来了一封新邮件,我们点击通知栏,系统会为我们打开最新收到的邮件,当我们看完邮件后,按返回键,我们并不会马上回到手机桌面的主屏上,而是先返回到收件箱界面,然后再返回到邮件APP的主界面,然后再返回到手机桌面的主屏上,它是按照邮件APP的页面队列返回的。
二:还是举刚才那个例子,当我们收到新邮件的通知后,我们点击打开新收到的邮件,当我们阅读完之后,我们想要点击返回键,立刻返回到我们刚刚所处的界面,继续进行刚才还在进行的任务。
这两种情况,在产品设计中,常常出现,所以我们也要想办法去实现,那么如何去实现这两种情况呢,我们一个一个来看。
首先请看第一种情况的代码:
- Intent notifyIntent = new Intent(this, NotifyRegularActivity.class);
- TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
- stackBuilder.addParentStack(NotifyRegularActivity.class);
- stackBuilder.addNextIntent(notifyIntent);
- // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
- int requestCode = (int) SystemClock.uptimeMillis();
- PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
- requestCode, PendingIntent.FLAG_UPDATE_CURRENT);
- notifyBuilder.setContentIntent(resultPendingIntent);
- <activity
- android:name="com.example.notificationtest.MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name="com.example.notificationtest.OtherActivity"
- android:label="OtherActivity"
- android:parentActivityName="com.example.notificationtest.MainActivity" >
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="com.example.notificationtest.MainActivity" />
- </activity>
- <activity
- android:name="com.example.notificationtest.NotifyRegularActivity"
- android:label="NotifyRegularActivity"
- android:parentActivityName="com.example.notificationtest.OtherActivity" >
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="com.example.notificationtest.OtherActivity" />
- </activity>
- TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
- stackBuilder.addParentStack(NotifyRegularActivity.class);
- stackBuilder.addNextIntent(notifyIntent);
我们给后面两个Activity,设置了这么一个属性android:parentActivityName,它指的就是该activity的返回路径,因为刚刚我们在调用addParentStack()这个方法的时候,设置的参数是NotifyRegularActivity.class所以根据上面配置文件的配置内容,那么它的返回堆栈的顺序就是:
需要注意的是,为了向下兼容版本,我们在设置android:parentActivityName这个属性的时候,还需要在配置文件中,为每个Activity进行如下设置:
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="com.example.notificationtest.MainActivity" />
- // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
- int requestCode = (int) SystemClock.uptimeMillis();
- PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
- requestCode, PendingIntent.FLAG_UPDATE_CURRENT);
- notifyBuilder.setContentIntent(resultPendingIntent);
1:PendingIntent.FLAG_UPDATE_CURRENT这个参数一般有四种选择分别是:
FLAG_CANCEL_CURRENT:如果构建的PendingIntent已经存在,则取消前一个,重新构建一个。
FLAG_NO_CREATE:如果前一个PendingIntent已经不存在了,将不再构建它。
FLAG_ONE_SHOT:表明这里构建的PendingIntent只能使用一次。
FLAG_UPDATE_CURRENT:如果构建的PendingIntent已经存在,那么系统将不会重复创建,只是把之前不同的传值替换掉。
如果没有特殊要求的话,我们常常会使用FLAG_UPDATE_CURRENT这个参数来构造PendingIntent,但是这样常常会引发第二个问题,什么问题呢?呵呵~
2:如上所述我们使用FLAG_UPDATE_CURRENT这个参数后,常常会发现,我们点击通知栏后,系统没有响应,时灵时不灵的,很是忧郁,这是为什么呢?原来使用FLAG_UPDATE_CURRENT这个参数后,系统不会重新创建新的PendingIntent,这样一来,如果你传递的Intent的 extra参数没有变化的话,那么系统就会认为你没有发送新的PendingIntent,这样就不会重新响应你的点击事件。一般情况下,为了能够区分每次的PendingIntent不一样,我们常常会在构造Intent的时候,设置不同的Action或者Extra值,这样一来,及时是使用FLAG_UPDATE_CURRENT这个参数,系统也会因为传值参数的变化而去响应每次的点击跳转事件。不过这种解决方法还是有些麻烦,有时候,我们根本不需要传递额外的Aciton或者参数值,这该怎么办呢?哈哈,解决代码已经在上面的代码中写出来了,在stackBuilder.getPendingIntent(requestCode, PendingIntent.FLAG_UPDATE_CURRENT)这个方法中,我们注意到第一个参数,这里,我们只要为这个参数设置一个独一无二的标识,那么刚刚提到的点击无响应的问题就迎刃而解了,我平时的设置办法就是利用这段代码:
- int requestCode = (int) SystemClock.uptimeMillis();
上面的讲解,我们就可以解决刚刚讨论的第一种情形了,下面我们来说一下,第二种情形,也就是点击返回键后,直接返回刚刚任务所处的界面,看看这个如何实现。来,看代码:
- Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);
- notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- // Creates the PendingIntent
- // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
- int requestCode = (int) SystemClock.uptimeMillis();
- PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,
- notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- notifyBuilder.setContentIntent(pendIntent);
- <activity
- android:name="com.example.notificationtest.NotifySpecialActivity"
- android:excludeFromRecents="true"
- android:label="NotifySpecialActivity"
- android:launchMode="singleTask"
- android:taskAffinity="" >
- </activity>
- notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Notificaton在平时的产品设计中,常常用来显示跟网络交互的进度,我们常常的做法是在通知栏上面,显示一个进度条,用来更新交互的进度,这个的实现方式很简单,主要依赖于mBuilder.setProgress()这个方法,具体的做法可以参考下面的代码:
- final NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
- this);
- mBuilder.setContentTitle("Picture Download")
- .setContentText("Download in progress")
- .setSmallIcon(R.drawable.small);
- new Thread(new Runnable() {
- @Override
- public void run() {
- int incr;
- for (incr = 0; incr <= 100; incr += 5) {
- // mBuilder.setProgress(100, incr, false);
- mBuilder.setProgress(0, 0, true);
- mNotifyManager.notify(NOTIFY_ID, mBuilder.build());
- try {
- Thread.sleep(1 * 1000);
- } catch (InterruptedException e) {
- }
- }
- mBuilder.setContentText("Download complete").setProgress(0, 0,
- false);
- mNotifyManager.notify(NOTIFY_ID, mBuilder.build());
- }
- }
- // Starts the thread by calling the run() method in its Runnable
- ).start();
- }
- mBuilder.setProgress(100, incr, false);
我们可以看见进度条的确切位置和进度情况。还有一种使用方法是这样的:
- mBuilder.setProgress(0, 0, true);
最后,当我们的任务完成后,我们需要取消进度条的显示,这时候我们需要调用如下方法:
- mBuilder.setContentText("Download complete").setProgress(0, 0,
- false);
Notification的进度条的使用方法就是这些,如果大家平时用的不多,最好还是根据上面贴出的源代码,自己联系一遍,稍候我也会把本次工程的源代码打包,上传到CSDN的资源库中,供大家参考。
上面跟大家介绍的,都是Notification的一种常规样式,自从Android4.1之后,谷歌引入了一种新的样式,叫做Big View,效果就是相对于传统的Notification,它的显示区域更大,显示的内容也更多一些。关于Big View,谷歌支持了三种模式,分别是:
Big picture style 和 Big text style 还有 Inbox style
在这里,我向大家重点介绍一下第一种样式和第三种样式,先给大家贴一下,这两种的效果图:
Big picture style
Inbox style
我们来看看代码是如何设置Big picture style 的:
- NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
- this).setSmallIcon(R.drawable.small)
- .setContentTitle("Picture tracker")
- .setContentText("Picture received");
- NotificationCompat.BigPictureStyle picStyle = new NotificationCompat.BigPictureStyle();
- Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bigpic);
- picStyle.bigPicture(bitmap);
- mBuilder.setStyle(picStyle);
- NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- mNotifyManager.notify(NOTIFY_ID, mBuilder.build());
接下来,我们再看看Inbox style这种样式是如何设置的:
- NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
- this).setSmallIcon(R.drawable.small)
- .setContentTitle("Inbox tracker")
- .setContentText("Inbox received");
- NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
- String[] events = new String[6];
- events[0] = "Hello my one world";
- events[1] = "Hello my two world";
- events[2] = "Hello my three world";
- events[3] = "Hello my four world";
- events[4] = "Hello my five world";
- events[5] = "Hello my six world";
- inboxStyle.setBigContentTitle("Inbox tracker details:");
- for (int i = 0; i < events.length; i++) {
- inboxStyle.addLine(events[i]);
- }
- inboxStyle.setBigContentTitle("Thers are six messages");
- inboxStyle.setSummaryText("It's so easy,right?");
- mBuilder.setStyle(inboxStyle);
- NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- mNotifyManager.notify(NOTIFY_ID, mBuilder.build());
通过上面的学习,想必大家已经对Notification有了一个比较全面的了解了,最后,我再给大家介绍一种自定义 Notification布局的用法。自定义Notification布局的app有很多,比如像墨迹天气,Clean Master等等,利用自定义布局,将用户所需信息和快捷功能,多样化的展示在通知栏上面,给大家看一下Clean Master的截图:
其实要是实现这种自定义布局的Notification,非常简单,我们这就给大家展示代码设置和布局配置:
先看看java代码:
- NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
- RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);
- remoteView.setTextViewText(R.id.text, "Custom Text");
- remoteView.setTextViewText(R.id.btn, "Custom Button");
- remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);
- Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);
- notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- // Creates the PendingIntent
- // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
- int requestCode = (int) SystemClock.uptimeMillis();
- PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,
- notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);
- mBuilder.setSmallIcon(R.drawable.small);
- mBuilder.setContent(remoteView);
- NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- mNotifyManager.notify(NOTIFY_ID, mBuilder.build());
- <?xml version="1.0" encoding="UTF-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="64dp" >
- <ImageView
- android:id="@+id/image"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentLeft="true"
- android:gravity="center" />
- <TextView
- android:id="@+id/text"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerInParent="true"
- android:gravity="center" />
- <Button
- android:id="@+id/btn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:gravity="center" />
- </RelativeLayout>
我们首先利用下面这行代码去解析上面的布局文件
- RemoteViews remoteView = new RemoteViews(getPackageName(),R.layout.remote);
- remoteView.setTextViewText(R.id.text, "Custom Text");
- remoteView.setTextViewText(R.id.btn, "Custom Button");
- remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);
- remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);
- Intent notifyIntent = new Intent(this, NotifySpecialActivity.class);
- notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- // Creates the PendingIntent
- // 当设置下面PendingIntent.FLAG_UPDATE_CURRENT这个参数的时候,常常使得点击通知栏没效果,你需要给notification设置一个独一无二的requestCode
- int requestCode = (int) SystemClock.uptimeMillis();
- PendingIntent pendIntent = PendingIntent.getActivity(this, requestCode,
- notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
最后,我们要调用下面这段代码,将自定义的RemoteView设置给notifyBuilder,然后调用发送通知的方法就OK了。
- mBuilder.setContent(remoteView);
- NotificationManager cancelNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- cancelNotificationManager.cancel(NOTIFY_ID);
- cancelNotificationManager.cancelAll();
cancelNotificationManager.cancelAll()这个方法是取消所有之前发布过的通知栏,比较暴力一点哈。
以上就是我今天给大家分享的内容,关于Notification的内容,在上面的内容中,可能还没有覆盖完所有的知识点,但是基本上涵盖了我平时工作中用到的几个关键用途,罗哩罗嗦的写了一大篇,可能有些地方没有讲清楚或者我理解的有错误,还希望大家能够帮我指点一二,共同进步。最后,还是老样子,附上本次所有示例代码的下载地址,方便大家调试学习:
下载地址:http://download.csdn.net/detail/pringlee2011/6960743
转载 http://blog.csdn.net/xy_nyle/article/details/19853591