安卓自定义Notification包含进度条时遇到的问题

最近在公司项目中为软件更新下载添加一个下载进度条,没想到本来应该是感觉很容易的事情,却花了我近1天的时间去搞定,特此记录一下,以防以后再遇到,同时希望能帮助那些遇到同意问题的同学们。首先我采用后台service异步下载

	downIntent = new Intent(activity, DownloadService.class);
	//传递下载地址
	downIntent.putExtra("url", payload.getDownloadUrl());
	//开启下载服务
	activity.startService(downIntent);


下载服务的代码相对比较简单

@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// 创建文件路径
		File tmpFile = new File(FILE_PATH);
		if (!tmpFile.exists()) {
			tmpFile.mkdir();
		}
		file = new File(FILE_PATH + FILE_NAME);
		//获取通知管理者
		manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		
		notif = new Notification();
		notif.icon = R.drawable.logo;
		notif.flags = Notification.FLAG_AUTO_CANCEL;
		// 设置点击通知安装软件
		Intent i = new Intent();
		i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		i.setAction(android.content.Intent.ACTION_VIEW);
		i.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
		PendingIntent pIntent = PendingIntent.getActivity(this, 0, i, 0);
		notif.contentIntent = pIntent;
		// 显示通知
		showNotification(0, true);
		// 开启异步下载
		DownAsyncTask task = new DownAsyncTask();
		// 设置正在下载标志,防止重复下载
		isDownLoad = true;
		task.execute(intent.getStringExtra("url"));
		return super.onStartCommand(intent, flags, startId);
	}
到这里,代码都还是比较常见的,大家在网上一搜一大把。当我做了一个通知包含进度条,并且需要动态更改进度的通知时,问题出现了,通知一旦开启,手机基本马上卡死,知道下载完成。在网上找了很久,大家的解决方法基本就是采用每次更新通知重新实例化contentView。

// 显示进度条
	private void showNotification(int progess, boolean isShow) {
		//每次更新进度条都重新实例化contentView
		notif.contentView = new RemoteViews(getPackageName(), R.layout.download_layout);
		notif.contentView.setProgressBar(R.id.download_progress, 100, progess, isShow);
		notif.contentView.setImageViewResource(R.id.download_logo, R.drawable.logo);
		notif.contentView.setTextViewText(R.id.download_percent, progess + "%");
		manager.notify(NOTIF_NUM, notif);
	}

照着大家的方法改完后发现,情况的确有所好转,不过手机依然会在进度条进度到5%的时候卡死。

然后又百度了很久,自己也分析了很久,终于被一篇网友的博客所启发,找到了卡死的源头。

		private int downloadCount = 0;

		@Override
		protected void onProgressUpdate(Double... values) {
			int i = (int) ((values[0] / values[1]) * 100);
			if (i >= 100) {
				showNotification(100, false);
			}
			// 每隔3%的进度才更新一次通知,防止通知卡死进程
			if (i - downloadCount >= 3) {
				downloadCount = i;
				showNotification(downloadCount, false);
			}
		}
在未优化之前,这里是直接调用显示通知方法的,这里有一个隐藏的问题,就是如果不加限制条件,而且网速又比较快的话,就会在短时间内,多次调用更新通知,从而造成手机卡死,我的解决方法很简单,只有当下载变化超过3%时才去更新通知。

最后附上完整下载service的源码

package com.boou.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import com.boou.goodlucklogisticscompany.R;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.IBinder;
import android.widget.RemoteViews;
import android.widget.Toast;

@SuppressLint({ "SdCardPath", "ShowToast" })
public class DownloadService extends Service {
	//下载的安装文件apk
	public static File file;
	//更新文件路径
	private static final String FILE_PATH = "/sdcard/BoouUpdate";
	//更新文件文件名
	private static final String FILE_NAME = "/updata.apk";
	// 是否处于下载状态
	public static boolean isDownLoad = false;
	// 通知管理器
	private NotificationManager manager;
	// 下载通知栏
	private Notification notif;
	//通知ID
	private static final int NOTIF_NUM = 2013;

	@Override
	public IBinder onBind(Intent intent) {

		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// 创建文件路径
		File tmpFile = new File(FILE_PATH);
		if (!tmpFile.exists()) {
			tmpFile.mkdir();
		}
		file = new File(FILE_PATH + FILE_NAME);
		//获取通知管理者
		manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		
		notif = new Notification();
		notif.icon = R.drawable.logo;
		notif.flags = Notification.FLAG_AUTO_CANCEL;
		// 设置点击通知安装软件
		Intent i = new Intent();
		i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		i.setAction(android.content.Intent.ACTION_VIEW);
		i.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
		PendingIntent pIntent = PendingIntent.getActivity(this, 0, i, 0);
		notif.contentIntent = pIntent;
		// 显示通知
		showNotification(0, true);
		// 开启异步下载
		DownAsyncTask task = new DownAsyncTask();
		// 设置正在下载标志,防止重复下载
		isDownLoad = true;
		task.execute(intent.getStringExtra("url"));
		return super.onStartCommand(intent, flags, startId);
	}

	// 显示进度条
	private void showNotification(int progess, boolean isShow) {
		//每次更新进度条都重新实例化contentView
		notif.contentView = new RemoteViews(getPackageName(), R.layout.download_layout);
		notif.contentView.setProgressBar(R.id.download_progress, 100, progess, isShow);
		notif.contentView.setImageViewResource(R.id.download_logo, R.drawable.logo);
		notif.contentView.setTextViewText(R.id.download_percent, progess + "%");
		manager.notify(NOTIF_NUM, notif);
	}

	class DownAsyncTask extends AsyncTask {
		@Override
		protected File doInBackground(String... params) {
			final String fileName = "updata.apk";
			File tmpFile = new File("/sdcard/BoouUpdate");
			if (!tmpFile.exists()) {
				tmpFile.mkdir();
			}
			final File file = new File("/sdcard/BoouUpdate/" + fileName);
			int num = 1;
			try {
				URL url = new URL(params[0]);
				try {
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					InputStream is = conn.getInputStream();
					int length = conn.getContentLength();
					FileOutputStream fos = new FileOutputStream(file);
					byte[] buf = new byte[256];
					conn.connect();
					double count = 0;
					if (conn.getResponseCode() >= 400) {
						Toast.makeText(getApplicationContext(), "连接超时", 1000).show();
					} else {
						while (count <= 100) {
							if (is != null) {
								int numRead = is.read(buf);
								if (numRead <= 0) {
									break;
								} else {
									publishProgress(new Double[] { (double) (256 * num), (double) length });
									fos.write(buf, 0, numRead);
									num++;
								}

							} else {
								break;
							}

						}
					}

					conn.disconnect();
					fos.close();
					is.close();
				} catch (IOException e) {

					e.printStackTrace();
				}
			} catch (MalformedURLException e) {

				e.printStackTrace();
			}

			return file;
		}

		private int downloadCount = 0;

		@Override
		protected void onProgressUpdate(Double... values) {
			int i = (int) ((values[0] / values[1]) * 100);
			if (i >= 100) {
				showNotification(100, false);
			}
			// 每隔3%的进度才更新一次通知,防止通知卡死进程
			if (i - downloadCount >= 3) {
				downloadCount = i;
				showNotification(downloadCount, false);
			}
		}

		@Override
		protected void onPostExecute(File result) {
			isDownLoad = false;
			file = result;
			// 询问安装
			CheckUpdate.openAsk();
		}
	}

}




你可能感兴趣的:(android,进度条卡死)