[2013.10.10]
Google官方文档有关于Notification的专题
一个好的应用一般都至少用到一个Notification,这东西用着挺方便的,花一上午研究一下,未来总会用得到。
Notification分成两种,一般的(Normal View)和大的(Big View)。
大的(Big View)在Android4.1以后支持,与普通的区别在于多了一块区域(Detail Area),具体区别如下图所示。
对于Notification本身没有什么特别的,从UE的角度有些需要注意的是工作堆栈不要冲突:
从Notification打开的Activity不应该影响原有Activity的工作堆栈,该Activity应该直接指向Notification中提到的数据,并且按back键后应该直接退回桌面。
这里有两种解决办法:
1,Regular Activity,即从新打开的Activity就是程序工作堆栈中的Activity。
2,Special Activity,新作一个Activity专门给Notification用。
对于第一种解决办法,需要用到TaskStackBuilder,这个类专门用于解决多任务堆栈时后退键的问题。
首先这个能够被复用的Activity要被声明成为:
<activity
android:name=".ResultActivity"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/>
</activity>
第5~6行为了向4.03之前兼容,为ResultActivity指定一个Parent Activity。第3行为4.1以后指定parent activity的方法。
下一步需要创建按后退时的Activity堆栈,
Intent resultIntent = new Intent(this, ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent to the top of the stack
stackBuilder.addNextIntent(resultIntent);
// Gets a PendingIntent 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());
注意第4行的addParentStack(),这里隐含指定开启这个Activity时用是启动一个全新的Activity堆栈(fresh task)。并且这一步并不会启动这个Activity,而是添加这个Activity的Parent Activity,即上面我们定义的MainActivity。
第6行的addNextIntent()用于启动该Activity,并使其位于task的栈顶。这样就能够做到按后退键直接回Home了。
在这个官方示例中并没有给出editIntentAt()的应用场景,这个方法用于编辑唤醒的Intent,这样可以在Intent中加一些信息用于启动时显示Notification中提到的内容。
第二种解决方案,定义Activity为:
<activity
android:name=".ResultActivity"
...
android:launchMode="singleTask"
android:taskAffinity=""
android:excludeFromRecents="true">
</activity>
...
android:taskAffinity=”"与LAG_ACTIVITY_NEW_TASK保证Activity不会进入默认任务堆栈(default task)。有默认affinity的Activity不会受影响。
android:excludeFromRecents=”true”保证用户不会navigate到这里。
对应的创建Notification代码如下:
// Instantiate a Builder object.
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Creates an Intent for the Activity
Intent notifyIntent =
new Intent(new ComponentName(this, ResultActivity.class));
// Sets the Activity to start in a new, empty task
notifyIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
// Creates the PendingIntent
PendingIntent notifyIntent =
PendingIntent.getActivity(
this,
0,
notifyIntent
PendingIntent.FLAG_UPDATE_CURRENT
);
// Puts the PendingIntent into the notification builder
builder.setContentIntent(notifyIntent);
// Notifications are issued by sending them to the
// NotificationManager system service.
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Builds an anonymous Notification object from the builder, and
// passes it to the NotificationManager
mNotificationManager.notify(id, builder.build());
对于状态栏中显示进度,在4.0以后直接setProgress即可,之前的版本需要自己设计View。
进度分为determinate与indeterminate两种。这里只给出前者的例子:
...
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.ic_notification);
// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
@Override
public void run() {
int incr;
// Do the "lengthy" operation 20 times
for (incr = 0; incr <= 100; incr+=5) {
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder.setProgress(100, incr, false);
// Displays the progress bar for the first time.
mNotifyManager.notify(0, mBuilder.build());
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep(5*1000);
} catch (InterruptedException e) {
Log.d(TAG, "sleep failure");
}
}
// When the loop is finished, updates the notification
mBuilder.setContentText("Download complete")
// Removes the progress bar
.setProgress(0,0,false);
mNotifyManager.notify(ID, mBuilder.build());
}
}
// Starts the thread by calling the run() method in its Runnable
).start();
后者只需要改一下mBuilder.setProgress(0, 0, true);即可。
如需要自定义Notification的Layout,需要用到 RemoteViews,这里不过多研究了。