Notification使用详解之二:可更新进度的通知

上次和大家分享了关于Notification的基础应用,包括简单的通知和自定义视图的通知。今天和大家分享一下如何实现一个可更新进度的通知。

我们将会模拟一个下载任务,先启动一个线程负责模拟下载工作,在这个过程中更新进度信息,然后下载线程把最新的进度信息以消息的形式,发送到UI线程的消息队列中,最后UI线程负责根据最新的进度信息来更新进度通知的UI界面。

好,大概就是这个步骤。接下来我们根据具体的实例来演示一下这个过程。

我们新建一个notification项目,然后修改/res/layout/main.xml布局文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:id="@+id/download"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="download"
        android:onClick="download"/>
    <Button
        android:id="@+id/cancel"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="cancel"
        android:onClick="cancel"/>
</LinearLayout>

注意,为了使示例中的Java代码看起来结构更加清晰,我们将按钮的点击事件都定义在布局文件中。

然后再来看一下MainActivity.java的代码:

package com.scott.notification;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.RemoteViews;

public class MainActivity extends Activity {

	private static final int NOTIFY_ID = 0;

	private boolean cancelled;

	private NotificationManager mNotificationManager;
	private Notification mNotification;

	private Context mContext = this;

	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case 1:
				int rate = msg.arg1;
				if (rate < 100) {
					// 更新进度
					RemoteViews contentView = mNotification.contentView;
					contentView.setTextViewText(R.id.rate, rate + "%");
					contentView.setProgressBar(R.id.progress, 100, rate, false);
				} else {
					// 下载完毕后变换通知形式
					mNotification.flags = Notification.FLAG_AUTO_CANCEL;
					mNotification.contentView = null;
					Intent intent = new Intent(mContext, FileMgrActivity.class);
					PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
					mNotification.setLatestEventInfo(mContext, "下载完成", "文件已下载完毕", contentIntent);
				}

				// 最后别忘了通知一下,否则不会更新
				mNotificationManager.notify(NOTIFY_ID, mNotification);
				break;
			case 0:
				// 取消通知
				mNotificationManager.cancel(NOTIFY_ID);
				break;
			}
		};
	};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}

	public void download(View view) {
		mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

		int icon = R.drawable.down;
		CharSequence tickerText = "开始下载";
		long when = System.currentTimeMillis();
		mNotification = new Notification(icon, tickerText, when);

		// 放置在"正在运行"栏目中
		mNotification.flags = Notification.FLAG_ONGOING_EVENT;

		RemoteViews contentView = new RemoteViews(mContext.getPackageName(), R.layout.download_notification_layout);
		contentView.setTextViewText(R.id.fileName, "AngryBird.apk");
		// 指定个性化视图
		mNotification.contentView = contentView;

		// intent为null,表示点击通知时不跳转
		PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, null, 0);
		// 指定内容意图
		mNotification.contentIntent = contentIntent;

		mNotificationManager.notify(NOTIFY_ID, mNotification);

		new Thread() {
			public void run() {
				startDownload();
			};
		}.start();
	}

	public void cancel(View view) {
		cancelled = true;
	}

	private void startDownload() {
		cancelled = false;
		int rate = 0;
		while (!cancelled && rate < 100) {
			try {
				// 模拟下载进度
				Thread.sleep(500);
				rate = rate + 5;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			Message msg = handler.obtainMessage();
			msg.what = 1;
			msg.arg1 = rate;
			handler.sendMessage(msg);
		}
		if (cancelled) {
			Message msg = handler.obtainMessage();
			msg.what = 0;
			handler.sendMessage(msg);
		}
	}
}

  

值得注意的是,在控制下载线程时使用了cancelled这个boolean值标志变量,对于线程的控制更好一些,不建议使用Thread.interrupt()去中断一个线程。另外,对于更新通知的UI界面时,要记住调用NotificationManager.notify(int id, Notification notification)方法通知一下,否则即使设置了新值,也不会起作用的。

程序中用到的带进度的通知布局/res/layout/download_notification_layout.xml布局文件代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:padding="3dp">
  <ImageView
      android:id="@+id/imageView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_margin="3dp"
      android:src="@drawable/down"/>
  <TextView
      android:id="@+id/fileName"
      android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_toRightOf="@id/imageView"
    android:layout_alignBottom="@id/imageView"
    android:gravity="center_vertical"
    android:textColor="#000"/>
  <TextView
      android:id="@+id/rate"
      android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/imageView"
    android:layout_alignRight="@id/imageView"
    android:gravity="center"
    android:text="0%"
    android:textColor="#000"/>
  <ProgressBar 
      android:id="@+id/progress"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/fileName"
    android:layout_alignLeft="@id/fileName"
    android:max="100"
    android:progress="0"/>
</RelativeLayout>

该通知的布局使用了相对布局,更加灵活易用,所以推荐大家多使用相对布局。

对于MainActivity.java中涉及到的FileMgrActivity,它是一个简单的界面,这里就不在介绍了,that's not the point。

最后我们跑一下程序,看看效果如何:

貌似还不错,好了,今天先到这里,下次再找机会分享。

posted @ 2016-03-13 11:49  znyyjk  阅读(688)  评论(0编辑  收藏  举报