LZ阅读的是中文翻译版本:http://hukai.me/android-training-course-in-chinese/basics/activity-lifecycle/recreating.html,试验机系统版本7.1。
10、Android交互设计
10.3 通知提示用户
10.3.1 建立Notification
以下的例子都是基于NotificationCompat.Builder,它在Support Library中。
创建Notification时,可以用NotificationCompat.Builder指定Notification的UI内容与行为。一个Builder至少包含以下内容:
- 一个小的icon,用setSmallIcon方法设置
- 一个标题,用setContentTitle方法设置
- 详细的文本内容,用setContentText方法设置
如
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!");
行为可以让用户从Notification进入App的Activity,在这个Activity中他们可以查看引起Notification的事件或者做下一步的处理。在Notification中,行为本身是由PendingIntent定义的,PendingIntent包含了一个启动App内Activity的Intent。
如何构建一个PendingIntent取决于要启动的Activity的类型。当从Notification中启动一个Activity时,必须保存用户的导航体验。
Intent resultIntent = new Intent(this, ResultActivity.class);
...
// Because clicking the notification opens a new ("special") activity, there's
// no need to create an artificial back stack.
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
可以通过调用Notification.Builder的setContentIntent方法将上一步定义的Notification的行为添加进去
PendingIntent resultPendingIntent;
...
mBuilder.setContentIntent(resultPendingIntent);
步骤:
- 获取一个NotificationManager对象
- 调用Notification.Builder对象的build方法创建通知
- 调用NotificationManager对象的notify方法完成发布通知的操作
NotificationCompat.Builder mBuilder;
...
// Sets an ID for the notification
int mNotificationId = 001;
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Builds the notification and issues it.
mNotifyMgr.notify(mNotificationId, mBuilder.build());
10.3.2 启动Activity时保留导航
设置一个常规的ActivityPendingIntent
设置一个直接启动的入口Activity的PendingIntent,遵循以下步骤:
1、在Manifest中定义application的Activity层次,最终的Manifest文件应该像下面这样:
<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的Intent中创建一个返回栈,如:
int id = 1;
...
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());
一个特定的Activity不需要一个返回栈,所以你不需要在Manifest中定义Activity的层次,你也不需要调用addParentStack方法去构建一个返回栈。作为代替,你需要用Manifest设置Activity任务选项,以及调用getActivity方法创建PendingIntent
1、Manifest中,在Activity的标签中增加下列属性:
- android:name="activityclass" Activity的完整类名
- android:taskAffinity="" 结合代码里设置的FLAG_ACTIVITY_NEW_TASK标识,确保这个Activity不会进入Application的默认任务。任何与Application的默认任务有密切关系的任务都不会受到影响
- android:excludeFromRecents="true" 将新任务从最近列表中排除,目的是为了避免用户不小心返回到它
2、建立以及发布通知:
a、创建一个启动Activity的Intent
b、通过调用setFlags方法并设置标识FLAG_ACTIVITY_NEW_TASK与FLAG_ACTIVITY_CLEAR_TASK,来设置Activity在一个新的,空的任务中启动
c、在Intent中设置其他需要的选项
d、通过调用getActivity方法从Intent中创建一个PendingIntent,你可以把这个PendingIntent当做setContentIntent的参数来使用
// 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(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.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());
10.3.3 更新Notification
当你需要对同一事件发布多次通知时,你应该避免每次都生成一个新的通知对象。相反,你应该考虑去更新先前的通知对象,或者改变它的值,或者增加一些值,或者两者同时进行。
更新一个通知
想要创建一个可以被更新的通知,需要在发布它的时候调用NotificationManager的notify(id,notification)方法为它指定一个id。更新一个已经发布的通知,需要更新或者创建一个Notification.Builder对象,并从这个对象创建一个Notification对象,然后用与先前一样的id去发布这个Notification。
如:
mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Sets an ID for the notification, so it can be updated
int notifyID = 1;
mNotifyBuilder = new NotificationCompat.Builder(this)
.setContentTitle("New Message")
.setContentText("You've received new messages.")
.setSmallIcon(R.drawable.ic_notify_status)
numMessages = 0;
// Start of a loop that processes data and then notifies the user
...
mNotifyBuilder.setContentText(currentText)
.setNumber(++numMessages);
// Because the ID remains unchanged, the existing notification is
// updated.
mNotificationManager.notify(
notifyID,
mNotifyBuilder.build());
...
移除Notification
Notification将持续可见,除非下面任何一种情况发生:
- 用户通过通知抽屉清除单独的或者所有通知
- 你在创建通知时调用了Notification.Builder的setAutoCancel(true)方法
- 你为一个指定了id的Notification调用了NotificationManager的cancel(id)方法
- 你调用了NotificationManager的cancelAll方法
10.3.5 显示Notification进度
展示固定长度的进度指示器
为了展示一个确定长度的进度条,调用setProgress(max, progress, false)方法将进度条添加进Notification,然后发布,第三个参数是个boolean类型变量,决定进度条是不确定的(true)还是确定的(false)。在你操作进行时,增加progress,更新Notification。在操作结束时,progress应该等于max。一个常用的调用setProgress的方法是设置max为100,然后增加progress就像做做的“完成百分比”。
当操作完成的时候,你可以选择让进度条继续展示,或者移除它。无论哪种情况下,记得更新Notification的文字来显示操作完成。
移除进度条,可以通过调用setProgress(0, 0, false)方法来实现。
int id = 1;
...
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(id, 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();
展示持续活动的指示器
为了展示一个持续活动的指示器,用setProgress(0, 0, true)方法把指示器添加进Notification,然后发布。前两个参数忽略,第三个参数表示进度是不确定的。
在操作开始的时候发布Notification,动画将会一直进行直到你更新Notification。当操作完成时,调用setProgress(0, 0, false)方法,然后更新Notification来移除这个动画指示器。一定要这么做,否则即使你操作完成了,动画还是会在那继续运行。同时也要记得更新Notification的文字来显示操作完成。
基本的代码和上面差不多,只要将下面这行修改一下
// Sets the progress indicator to a max value, the current completion
// percentage, and "determinate" state
mBuilder.setProgress(100, incr, false);
改为
// Sets an activity indicator for an operation of indeterminate length
mBuilder.setProgress(0, 0, true);