有时候,我们会涉及到这么一个需求,那就是,产品设计,希望我们能够监听 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); //需要一个导航堆栈来将一些Activity进行存储,方便返回
- 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);
- <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,但是这样常常会引发第二个问题,什么问题呢?呵呵~
- 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();
- }
- 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());
首先我们实例化一个NotificationCompat.BigPictureStyle,然后读取要展示的图片资源,调用picStyle.bigPicture(bitmap)这个方法设置图片,最后调用notifyBuilder的mBuilder.setStyle(picStyle)方法,设置好BIG VIEW的样式,就OK了,代码简单的令人发指,我就不多解释了,大家参考上面的示例代码即可。
接下来,我们再看看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,非常简单,我们这就给大家展示代码设置和布局配置:
先看看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布局文件是什么样的:
- <?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);
然后根据每个控件的id号进行资源设置:
- remoteView.setTextViewText(R.id.text, "Custom Text");
- remoteView.setTextViewText(R.id.btn, "Custom Button");
- remoteView.setImageViewResource(R.id.image, R.drawable.ic_launcher);
我们也可以为这些控件单独设置点击事件,比如设置Button的点击事件:
- remoteView.setOnClickPendingIntent(R.id.btn, pendIntent);
上面第二个参数pendingIntent的获取,在之前的讲解中,已经介绍了好几种方式了,这里我们随便选择一种来实现了:
- 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);
最后的最后,需要再给大家介绍两个方法,那就是通过代码来取消Notification,咱不能只管杀不管埋啊,哈哈~
- NotificationManager cancelNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- cancelNotificationManager.cancel(NOTIFY_ID);
- cancelNotificationManager.cancelAll();
cancelNotificationManager.cancel(NOTIFY_ID)这个方法是根据之前发布通知时,分配的ID号,来取消对应的通知栏。 cancelNotificationManager.cancelAll()这个方法是取消所有之前发布过的通知栏,比较暴力一点哈。