Android Notification I-创建和使用方法

来源:互联网 发布:淘宝新店宝贝上架 编辑:程序博客网 时间:2024/05/16 13:59

概述:

Notification是可以显示在APP外的给用户看的信息, 这东西一般显示在屏幕的顶部,当我们告诉Android要显示一个notification的时候, 它首先会以一个小图标的方式出现在notification area. 如果用户想要查看详情, 他可以打开notification drawer. Notification area和notification drawer都是有Android控制的让用户可以使用看到的区域. 这是手机上的notification area:


下面这个是notification drawer:


创建一个Notification:

想要创建一个Notification, 我们需要Notification.Builder对象, 并为其指定UI和动作. 然后使用Notification.Builder.build()方法返回一个Notification对象. 想要使用这个Notification对象的话, 我们则需要调用NotificationManager.notify()方法.
一个Notification对象必须包含下列的部分:

一个小的icon, 通过setSmallIcon()指定.

一个title, 通过setContentTitle()指定.

默认文本, 通过setContentText()指定.

除了上述的3个部分之外, 其它的部分则都是可选的.

 

Notification的动作(action):

Notification的action(动作)是可选的, 但是我们应该至少为其指定一个action, 它让用户可以通过点击action启动一个Activity, 在APP的内部还可以对该动作进行更多的操作.

一个Notification可以提供多个action, 我们应该总是提供一个点击事件的action, 通常情况下这个action会打开一个我们APP内部的Activity. 我们还可以在Notification上增加按钮, 以实现比如回复一条文字消息这种操作(Android4.1加入).

在Notification内部, action本身是由一个PendingIntent定义的, 其中包含一个Intent, 可以启动一个APP内部的Activity. 为了将PendingIntent与某个手势关联, 我们需要调用NotificationCompat.Builder中的方法. 比如, 如果我们需要在用户点击Notification的时候启动一个Activity,那么需要通过setContentIntent()来添加一个PendingIntent.

当用户点击Notification的时候启动一个Activity可能是最常用的操作了, 我们还可以在用户关闭一个Notification的时候启动一个Activity. 在Android4.1及以上的版本中, 我们可以通过Notification上的按钮来启动一个Activity.

 

Notification的优先级(priority):

如果有需要的话我们可以为Notification设置优先级, 优先级指定了设备UI应该如何显示Notification. 我们可以调用NotificationCompat.Builder.setPriority()方法并传入一个NotificationCompat优先级常量给它作为参数. 有5个优先级等级, 从PRIORITY_MIN(-2)到PRIORITY_MAX(2),如果没设置的话, 那么默认的优先级是PRIORITY_DEFAULT(0).

 

创建一个简单的Notification:

下面的代码是一个简单的Notification, 在用户点击Notification的时候会打开一个Activity. 留意代码中的TaskStackBuilder对象, 它为action创建了一个PendingIntent, 这种方法在下文还会有更详细的介绍. 栗子:

NotificationCompat.Builder mBuilder=
        new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!");
// Creates anexplicit intent for an Activity in your app
Intent resultIntent = new Intent(this,ResultActivity.class);

// The stackbuilder object will contain an artificial back stack for the
// startedActivity.
// This ensuresthat navigating backward from the Activity leads out of
// yourapplication to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the backstack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ResultActivity.class);
// Adds theIntent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
        );
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allowsyou to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());

这时我们的用户就已经收到一个提醒了.

 

为Notification指定一个layout:

如果想要为我们的Notification指定一个自己的布局, 那么首先需要创建一个带有普通view的NotificationCompat.Builder对象. 然后调用Builder.setStyle(),并传入一个扩展的layout对象作为它的参数. 但是这种方法不适用于Android4.1及以前的版本, 下面的代码展示了如何将之前的那段代码扩展为指定的layout:

NotificationCompat.Builder mBuilder=new NotificationCompat.Builder(this)
    .setSmallIcon(R.drawable.notification_icon)
    .setContentTitle("Event tracker")
    .setContentText("Events received")
NotificationCompat.InboxStyle inboxStyle=
        new NotificationCompat.InboxStyle();
String[] events=new String[6];
// Sets a titlefor the Inbox in expanded layout
inboxStyle.setBigContentTitle("Event tracker details:");
...
// Moves eventsinto the expanded layout
for (int i=0; i< events.length; i++){

    inboxStyle.addLine(events[i]);
}
// Moves theexpanded layout object into the notification object.
mBuilder.setStyle(inBoxStyle);
...
// Issue thenotification here.

 

关于兼容性的处理:

不是所有的Notification的特性都可以在特定的版本可以得到支持的, 比如action button, 只有在Android4.1及以上版本中才能够得到支持, 因为扩展Notification本身就需要Android4.1以上的版本. 为了获得更好的兼容性, 我们可以使用NotificationCompat和它的子类, 特别是NotificationCompat.Builder. 另外, 当我们实现一个Notification的时候应该遵循这些流程:

1.      向所有的用户提供所有的Notification功能, 不要在意他们的版本. 为了实现这个, 需要确保所有的功能在我们的APP中的某个Activity中是可用的. 比如, 如果我们想要使用addAction()提供一个控制媒体播放和停止播放的操作, 那么首先应该在我们自己的Activity中实现这个操作.

2.      确保所有的用户可以在Activity中使用这个功能, 为了实现这个, 需要为Activity创建一个PendingIntent. 调用setContentIntent()方法将PendingIntent传给Notification.

3.      现在可以添加Notification的扩展功能到你想要使用的Notification中了. 请记住任何功能都应该在点击启动的Activity中可用. 比如我们要扩展一个可以用于聊天的Notification, 那么必须保证点击这个Notification打开的那个Activity中, 也可以实现聊天的功能.

 

管理Notification:

当我们多次使用同一个Notification的时候, 我们应该考虑修改之前使用过的Notification的值或者对其添加数据, 而不是重新创建一个新的Notification. 比如Gmail通过增加未读消息的数量和增加email的概述到Notification来提醒用户新邮件到了. 这种方法叫做”stacking(堆叠)” Notification(Gmail的这个功能用到了”inbox”扩展layout, 只有在Android4.1以上才支持). 在这里对这个概念有更多的阐述.

下面开始描述如何更新Notification和如何删除它们.

更新Notification:

想要将一个Notification设置为可更新的Notification, 我们需要使用NotificationManager.notify()方法来显示它, 并传入一个NotificationID作为参数. 如果想要在创建Notification之后就更新它, 那么需要创建一个NotificationCompat.Builder, 通过该Builder创建一个Notification,然后使用与之前相同的ID发布这个新的Notification. 如果之前的Notification依然是可见的, 那么Android将会更新该Notification为新的内容. 如果之前的Notification已经消失了, 那么会创建一个新的.

这里是一段更新Notification的代码:

mNotificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Sets an IDfor the notification, so it can be updated
int notifyID =1;
mNotifyBuilder = newNotificationCompat.Builder(this)
    .setContentTitle("New Message")
    .setContentText("You've received new messages.")
    .setSmallIcon(R.drawable.ic_notify_status)
numMessages = 0;
// Start of aloop that processes data and then notifies the user
...
    mNotifyBuilder.setContentText(currentText)
        .setNumber(++numMessages);
    // Because theID remains unchanged, the existing notification is
    // updated.
    mNotificationManager.notify(
            notifyID,
            mNotifyBuilder.build());
...

删除Notification:

在下列的任何一个事件发生之前, Notification会一直存在;

1.      用户选择删除Notification或者执行了”clear all”.

2.      用户点击了Notification, 并且我们在创建该Notification的时候调用了setAutoCancel()方法.

3.      APP自己调用了cancel()并指定了NotificationID. 这个方法也会删除”ongoing”Notification.

4.      APP自己调用了cancelAll()方法, 会删除之前所有APP发布的Notification.

 

当启动一个Activity的时候保留导航:

当我们从Notification启动一个Activity的时候, 必须考虑到用户预期的导航体验. 点击退后的时候应该回到APP的正常流程, 比如到主界面. 考虑到用户的体验, 我们应该在一个新的Task中启动Activity. 我们如何设置PendingIntent以获得一个新的Task取决于我们要启动的Activity的性质. 这里有两种常用的解决方案:

1.      常规Activity. 就是我们的APP中已经存在的Activity, 平时不通过Notification也可以用到这个Activity. 在这种情况下, 需要设置PendingIntent启动一个新的Task, 并且提供Task后的堆栈, 这样用户在进入了这个Activity之后的后退事件就可以得到处理了.

Gmail的Notification刚好演示了这种功能. 当我们点击一个单一message的Notification的时候, 我们可以看到message本身. 点击后退按钮的时候会让我们退回到桌面, 就好像我们从桌面直接启动Gmail, 而不是从Notification启动它. 这种情况会在点击Notification的时候发生, 点击Notification所处的位置. 比如我们正在Gmail中写一个email, 这时候点击了一个带有新的email的Notification, 我们会直接被导航到这个email, 点击返回键的时候会被导航到邮箱列表, 然后到主界面(Android桌面), 而不是带回到之前写email的地方.

2.      特殊Activity. 用户只能从Notification启动这个Activity. 在某种意义上说这个Activity只是为了显示Notification未能全部显示的信息. 在这种情况下, 需要设置一个PendingIntent来启动一个新的Task. 但是不需要创建一个堆栈(不需要考虑按回退键), 因为启动的Activity不是APP中的Activity的一部分. 点击后退键的时候将会让用户回到Android的主界面.

那么现在开始看一下如何启动上述两种Activity.

设置一个常规Activity的PendingIntent:

设置常规Activity的PendingIntent的步骤是酱婶儿的:

1.      在Manifest中定义一个Activity.

A.     为Android4.0.3和更早的版本提供支持, 需要这样做, 通过<meta-data>指定Activity的父Activity,

B.     为Android4.1及更新的版本提供支持, 需要这样做, 为<activity>指定android:parentActivityName属性.

最后的XML文件长这样:

<activity
    android:name=".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=".ResultActivity"
    android:parentActivityName=".MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=".MainActivity"/>
</activity>

2.      为Activity指定堆栈, 也就是为了按下返回键时候的反应.

A.     创建一个Intent来启动Activity.

B.     通过TaskStackBuilder.create()方法创建一个堆栈(stack).

C.     通过addParentStack()向stack builder中添加堆栈(stack).

D.     通过addNextIntent()方法为要启动的Activity指定Intent. 传入步骤A中创建的Intent.

E.      如果需要的话可以向Intent对象中添加参数, 需要使用TaskStackBuilder.editIntentAt(), 在有些情况下需要保证按返回键后显示的Activity是有意义的, 所以可能会用到这样的功能.

F.      通过getPendingIntent()方法取得PendingIntent, 然后我们可以使用这个PendingIntent作为setContentIntent()方法的参数.

下面的代码段描述了这一过程:

...
Intent resultIntent = new Intent(this,ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the backstack
stackBuilder.addParentStack(ResultActivity.class);
// Adds theIntent to the top of the stack
stackBuilder.addNextIntent(resultIntent);
// Gets aPendingIntent containing the entire back stack
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
...
NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
builder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, builder.build());

设置一个特殊Activity的PendingIntent:

特殊Activity不需要一个堆栈, 所以我们不需要调用addParentStack()来创建一个堆栈. 但是需要在manifest中设置Activity的Task选项, 并通过getActivity()来创建PendingIntent.

1.      在manifest中, 为Activity增加以下属性:

android:name=”activityclass:Activity的完整的类名.

android:taskAffinity=””:跟FLAG_ACTIVITY_NEW_TASK标志一起使用可以确保Activity不被分配到系统默认的task中.

android:excludeFromRecents=”true”:从”最近使用”中排出新的task, 这样用户就不能通过导航回到这个activity了.

<activity
    android:name=".ResultActivity"
...
    android:launchMode="singleTask"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>
...

2.      创建并发布一个Notification:

A.     创建一个需要启动的Activity的Intent.

B.     通过setFlag()设置FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK来设置Activity被创建在一个新的空的task中.

C.     对Intent设置任何其它想要设置的选项.

D.     通过getActivity()创建一个PendingIntent. 我们可以使用这个PendingIntent作为setContentIntent()方法的参数.

下面的代码段描述了这一过程:

// Instantiate a Builder object.
NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
// Creates anIntent for the Activity
Intent notifyIntent =
        new Intent(this,ResultActivity.class);
// Sets theActivity to start in a new, empty task
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                       | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Creates thePendingIntent
PendingIntent notifyPendingIntent =
        PendingIntent.getActivity(
        this,
        0,
        notifyIntent,
        PendingIntent.FLAG_UPDATE_CURRENT
);

// Puts thePendingIntent into the notification builder
builder.setContentIntent(notifyPendingIntent);
// Notificationsare issued by sending them to the
//NotificationManager system service.
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Builds ananonymous Notification object from the builder, and
// passes it tothe NotificationManager
mNotificationManager.notify(id, builder.build());

在Notification中显示进度:

Notification中可以包含一个进度条用来显示进度. 如果我们可以确定执行操作需要的时间那么就可以使用一个进度条, 如果不能确定, 那么就得使用一种”不确定”的指示器. 显示进度条需要ProgressBar类, 从Android4.0开始, 显示一个进度条使用setProgress()方法, 对于更早的版本, 我们必须创建自己自定义的Notification layout, 并且包含一个ProgressBar的控件.

显示进度条:

要显示这样的一个进度条, 就得先调用setProgress(max, progress, false)方法来添加一个bar到Notification上面, 然后再发布这个Notification.随着进度的增加, 增加参数中的progress, 然后更新Notification. 在进度条走到终点的时候, progress参数应该跟max相等. 一个常用的方法是将max设置为100, 然后按照百分比来调整progress.

Progress bar在进度走完或者我们主动移除它的情况下会消失,不管是主动的还是已经走完了, 我们都应该记得在结束之后修改Notification的说明文字, 想要移除Notification的话, 可以使用setProgress(0, 0, false)方法. 栗子:

...
mNotifyManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = newNotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
    .setContentText("Download in progress")
    .setSmallIcon(R.drawable.ic_notification);
// Start alengthy operation in a background thread
new Thread(
    new Runnable(){
        @Override
        public void run(){
            int incr;
            // Do the "lengthy" operation 20times
            for (incr=0; incr<=100; incr+=5){
                    // Sets the progress indicator to a maxvalue, the
                    // current completion percentage, and"determinate"
                    // state
                    mBuilder.setProgress(100, incr,false);
                    // Displays the progress bar for thefirst time.
                   mNotifyManager.notify(0, mBuilder.build());
                       // Sleeps thethread, simulating an operation
                       // that takestime
                       try {
                           // Sleep for 5 seconds
                           Thread.sleep(5*1000);
                       } catch (InterruptedException e){
                           Log.d(TAG,"sleep failure");
                       }
            }
            // When the loop is finished, updates thenotification
            mBuilder.setContentText("Download complete")
            // Removes the progress bar
                    .setProgress(0,0,false);
            mNotifyManager.notify(ID, mBuilder.build());
        }
    }
// Starts thethread by calling the run() method in its Runnable
).start();

显示一个持续活动的指示器:

要显示一个不确定(进度)的指示器, 我们需要调用setProgress(0, 0, true)(前两个参数是忽略的)方法来将其添加到Notification然后发布这个Notification.结果是跟progress bar一样风格的指示器, 但是它是持续不停的. 一旦操作开始, 动画将会在我们修改Notification之前一直持续直到我们调用setProgress(0, 0, false)并且更新Notification移除它为止. 完成之后还要记得修改Notification的文字描述. 栗子:

将上一段代码中的这个部分:

// Sets the progress indicator to a max value, thecurrent completion
// percentage,and "determinate" state
mBuilder.setProgress(100, incr,false);
// Issues thenotification
mNotifyManager.notify(0, mBuilder.build());

修改为:

 // Sets anactivity indicator for an operation of indeterminate length
mBuilder.setProgress(0,0,true);
// Issues thenotification
mNotifyManager.notify(0, mBuilder.build());

 

参考: http://developer.android.com/guide/topics/ui/notifiers/notifications.html
0 0