Notification使用詳解之二:可更新進度的通知

encienqi發表於2012-07-28

上次和大家分享了關於Notification的基礎應用,包括簡單的通知和自定義檢視的通知。今天和大家分享一下如何實現一個可更新進度的通知。

我們將會模擬一個下載任務,先啟動一個執行緒負責模擬下載工作,在這個過程中更新進度資訊,然後下載執行緒把最新的進度資訊以訊息的形式,傳送到UI執行緒的訊息佇列中,最後UI執行緒負責根據最新的進度資訊來更新進度通知的UI介面。

好,大概就是這個步驟。接下來我們根據具體的例項來演示一下這個過程。

我們新建一個notification專案,然後修改/res/layout/main.xml佈局檔案,程式碼如下:

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent">  
  6.     <Button  
  7.         android:id="@+id/download"  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="download"  
  11.         android:onClick="download"/>  
  12.     <Button  
  13.         android:id="@+id/cancel"  
  14.         android:layout_width="fill_parent"  
  15.         android:layout_height="wrap_content"  
  16.         android:text="cancel"  
  17.         android:onClick="cancel"/>  
  18. </LinearLayout>  

注意,為了使示例中的Java程式碼看起來結構更加清晰,我們將按鈕的點選事件都定義在佈局檔案中。

然後再來看一下MainActivity.java的程式碼:

[java] view plaincopy
  1. package com.scott.notification;  
  2.   
  3. import android.app.Activity;  
  4. import android.app.Notification;  
  5. import android.app.NotificationManager;  
  6. import android.app.PendingIntent;  
  7. import android.content.Context;  
  8. import android.content.Intent;  
  9. import android.os.Bundle;  
  10. import android.os.Handler;  
  11. import android.os.Message;  
  12. import android.view.View;  
  13. import android.widget.RemoteViews;  
  14.   
  15. public class MainActivity extends Activity {  
  16.   
  17.     private static final int NOTIFY_ID = 0;  
  18.   
  19.     private boolean cancelled;  
  20.   
  21.     private NotificationManager mNotificationManager;  
  22.     private Notification mNotification;  
  23.   
  24.     private Context mContext = this;  
  25.   
  26.     private Handler handler = new Handler() {  
  27.         public void handleMessage(android.os.Message msg) {  
  28.             switch (msg.what) {  
  29.             case 1:  
  30.                 int rate = msg.arg1;  
  31.                 if (rate < 100) {  
  32.                     // 更新進度  
  33.                     RemoteViews contentView = mNotification.contentView;  
  34.                     contentView.setTextViewText(R.id.rate, rate + "%");  
  35.                     contentView.setProgressBar(R.id.progress, 100, rate, false);  
  36.                 } else {  
  37.                     // 下載完畢後變換通知形式  
  38.                     mNotification.flags = Notification.FLAG_AUTO_CANCEL;  
  39.                     mNotification.contentView = null;  
  40.                     Intent intent = new Intent(mContext, FileMgrActivity.class);  
  41.                     PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);  
  42.                     mNotification.setLatestEventInfo(mContext, "下載完成""檔案已下載完畢", contentIntent);  
  43.                 }  
  44.   
  45.                 // 最後別忘了通知一下,否則不會更新  
  46.                 mNotificationManager.notify(NOTIFY_ID, mNotification);  
  47.                 break;  
  48.             case 0:  
  49.                 // 取消通知  
  50.                 mNotificationManager.cancel(NOTIFY_ID);  
  51.                 break;  
  52.             }  
  53.         };  
  54.     };  
  55.   
  56.     @Override  
  57.     public void onCreate(Bundle savedInstanceState) {  
  58.         super.onCreate(savedInstanceState);  
  59.         setContentView(R.layout.main);  
  60.     }  
  61.   
  62.     public void download(View view) {  
  63.         mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);  
  64.   
  65.         int icon = R.drawable.down;  
  66.         CharSequence tickerText = "開始下載";  
  67.         long when = System.currentTimeMillis();  
  68.         mNotification = new Notification(icon, tickerText, when);  
  69.   
  70.         // 放置在"正在執行"欄目中  
  71.         mNotification.flags = Notification.FLAG_ONGOING_EVENT;  
  72.   
  73.         RemoteViews contentView = new RemoteViews(mContext.getPackageName(), R.layout.download_notification_layout);  
  74.         contentView.setTextViewText(R.id.fileName, "AngryBird.apk");  
  75.         // 指定個性化檢視  
  76.         mNotification.contentView = contentView;  
  77.   
  78.         // intent為null,表示點選通知時不跳轉  
  79.         PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0null0);  
  80.         // 指定內容意圖  
  81.         mNotification.contentIntent = contentIntent;  
  82.   
  83.         mNotificationManager.notify(NOTIFY_ID, mNotification);  
  84.   
  85.         new Thread() {  
  86.             public void run() {  
  87.                 startDownload();  
  88.             };  
  89.         }.start();  
  90.     }  
  91.   
  92.     public void cancel(View view) {  
  93.         cancelled = true;  
  94.     }  
  95.   
  96.     private void startDownload() {  
  97.         cancelled = false;  
  98.         int rate = 0;  
  99.         while (!cancelled && rate < 100) {  
  100.             try {  
  101.                 // 模擬下載進度  
  102.                 Thread.sleep(500);  
  103.                 rate = rate + 5;  
  104.             } catch (InterruptedException e) {  
  105.                 e.printStackTrace();  
  106.             }  
  107.             Message msg = handler.obtainMessage();  
  108.             msg.what = 1;  
  109.             msg.arg1 = rate;  
  110.             handler.sendMessage(msg);  
  111.         }  
  112.         if (cancelled) {  
  113.             Message msg = handler.obtainMessage();  
  114.             msg.what = 0;  
  115.             handler.sendMessage(msg);  
  116.         }  
  117.     }  
  118. }  

值得注意的是,在控制下載執行緒時使用了cancelled這個boolean值標誌變數,對於執行緒的控制更好一些,不建議使用Thread.interrupt()去中斷一個執行緒。另外,對於更新通知的UI介面時,要記住呼叫NotificationManager.notify(int id, Notification notification)方法通知一下,否則即使設定了新值,也不會起作用的。

程式中用到的帶進度的通知佈局/res/layout/download_notification_layout.xml佈局檔案程式碼如下:

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.   android:layout_width="fill_parent"  
  4.   android:layout_height="fill_parent"  
  5.   android:padding="3dp">  
  6.   <ImageView  
  7.     android:id="@+id/imageView"  
  8.     android:layout_width="wrap_content"  
  9.     android:layout_height="wrap_content"  
  10.     android:layout_margin="3dp"  
  11.     android:src="@drawable/down"/>  
  12.   <TextView  
  13.     android:id="@+id/fileName"  
  14.     android:layout_width="fill_parent"  
  15.     android:layout_height="fill_parent"  
  16.     android:layout_toRightOf="@id/imageView"  
  17.     android:layout_alignBottom="@id/imageView"  
  18.     android:gravity="center_vertical"  
  19.     android:textColor="#000"/>  
  20.   <TextView  
  21.     android:id="@+id/rate"  
  22.     android:layout_width="fill_parent"  
  23.     android:layout_height="wrap_content"  
  24.     android:layout_below="@id/imageView"  
  25.     android:layout_alignRight="@id/imageView"  
  26.     android:gravity="center"  
  27.     android:text="0%"  
  28.     android:textColor="#000"/>  
  29.   <ProgressBar   
  30.     android:id="@+id/progress"  
  31.     style="?android:attr/progressBarStyleHorizontal"  
  32.     android:layout_width="fill_parent"  
  33.     android:layout_height="wrap_content"  
  34.     android:layout_below="@id/fileName"  
  35.     android:layout_alignLeft="@id/fileName"  
  36.     android:max="100"  
  37.     android:progress="0"/>  
  38. </RelativeLayout>  

該通知的佈局使用了相對佈局,更加靈活易用,所以推薦大家多使用相對佈局。

對於MainActivity.java中涉及到的FileMgrActivity,它是一個簡單的介面,這裡就不在介紹了,that's not the point。

最後我們跑一下程式,看看效果如何:

貌似還不錯,好了,今天先到這裡,下次再找機會分享

相關文章