Android Service下载文件并自定义通知提示下载
生活随笔
收集整理的这篇文章主要介绍了
Android Service下载文件并自定义通知提示下载
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
最近要做一个更新sdk,里面用到了service后台下载,自定义通知提示下载进度,下面直接贴上代码.
自定义通知 MyNotification.java package com.cnziz.updatelib.download;import com.cnziz.updatelib.R;import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.widget.RemoteViews;public class MyNotification {public final static int DOWNLOAD_COMPLETE = -2;public final static int DOWNLOAD_FAIL = -1;Context mContext; // Activity或Service上下文Notification notification; // notificationNotificationManager nm;String titleStr; // 通知标题String contentStr; // 通知内容PendingIntent contentIntent; // 点击通知后的动作int notificationID; // 通知的唯一标示IDint iconID; // 通知栏图标long when = System.currentTimeMillis();RemoteViews remoteView = null; // 自定义的通知栏视图/*** * @param context* Activity或Service上下文* @param contentIntent* 点击通知后的动作* @param id* 通知的唯一标示ID*/public MyNotification(Context context, PendingIntent contentIntent, int id) {// TODO Auto-generated constructor stubmContext = context;notificationID = id;this.contentIntent = contentIntent;this.nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);}/*** 显示自定义通知* * @param icoId* 自定义视图中的图片ID* @param titleStr* 通知栏标题* @param layoutId* 自定义布局文件ID*/public void showCustomizeNotification(int icoId, String titleStr,int layoutId) {this.titleStr = titleStr;notification = new Notification(R.drawable.ic_launcher, titleStr, when);notification.flags = Notification.FLAG_ONLY_ALERT_ONCE;notification.flags |= Notification.FLAG_AUTO_CANCEL;notification.contentIntent = this.contentIntent;// 1、创建一个自定义的消息布局 view.xml// 2、在程序代码中使用RemoteViews的方法来定义image和text。然后把RemoteViews对象传到contentView字段if (remoteView == null) {remoteView = new RemoteViews(mContext.getPackageName(), layoutId);remoteView.setImageViewResource(R.id.ivNotification, icoId);remoteView.setTextViewText(R.id.tvTitle, titleStr);remoteView.setTextViewText(R.id.tvTip, "开始下载");remoteView.setProgressBar(R.id.pbNotification, 100, 0, false);notification.contentView = remoteView;}nm.notify(notificationID, notification);}/*** 更改自定义布局文件中的进度条的值* * @param p* 进度值(0~100)*/public void changeProgressStatus(int p) {if (notification.contentView != null) {if (p == DOWNLOAD_FAIL)notification.contentView.setTextViewText(R.id.tvTip, "下载失败! ");else if (p == 100)notification.contentView.setTextViewText(R.id.tvTip,"下载完成,请点击安装");elsenotification.contentView.setTextViewText(R.id.tvTip, "进度(" + p+ "%)");notification.contentView.setProgressBar(R.id.pbNotification, 100,p, false);}nm.notify(notificationID, notification);}public void changeContentIntent(PendingIntent intent) {this.contentIntent = intent;notification.contentIntent = intent;}/*** 显示系统默认格式通知* * @param iconId* 通知栏图标ID* @param titleText* 通知栏标题* @param contentStr* 通知栏内容*/public void showDefaultNotification(int iconId, String titleText,String contentStr) {this.titleStr = titleText;this.contentStr = contentStr;this.iconID = iconId;notification = new Notification();notification.tickerText = titleStr;notification.icon = iconID;notification.flags = Notification.FLAG_INSISTENT;notification.flags |= Notification.FLAG_AUTO_CANCEL;notification.contentIntent = this.contentIntent;// 添加声音效果// notification.defaults |= Notification.DEFAULT_SOUND;// 添加震动,后来得知需要添加震动权限 : Virbate Permission// mNotification.defaults |= Notification.DEFAULT_VIBRATE ;// 添加状态标志// FLAG_AUTO_CANCEL 该通知能被状态栏的清除按钮给清除掉// FLAG_NO_CLEAR 该通知能被状态栏的清除按钮给清除掉// FLAG_ONGOING_EVENT 通知放置在正在运行// FLAG_INSISTENT 通知的音乐效果一直播放notification.flags = Notification.FLAG_ONLY_ALERT_ONCE;changeNotificationText(contentStr);}/*** 改变默认通知栏的通知内容* * @param content*/public void changeNotificationText(String content) {notification.setLatestEventInfo(mContext, titleStr, content,contentIntent);// 设置setLatestEventInfo方法,如果不设置会App报错异常// NotificationManager mNotificationManager = (NotificationManager)// getSystemService(Context.NOTIFICATION_SERVICE);// 注册此通知// 如果该NOTIFICATION_ID的通知已存在,会显示最新通知的相关信息 ,比如tickerText 等nm.notify(notificationID, notification);}/*** 移除通知*/public void removeNotification() {// 取消的只是当前Context的Notificationnm.cancel(notificationID);} }
下面是UpdateUtils.java ,告诉你如何使用
package com.cnziz.updatelib;import com.cnziz.updatelib.download.DownloadServices; import com.cnziz.updatelib.utils.Listener.onUpdateListener;import android.content.Context; import android.content.Intent;public class UpdateUtils {public static UpdateUtils mUpdateUtils;public static UpdateUtils getInstanse(){if (null == mUpdateUtils) {mUpdateUtils = new UpdateUtils();}return mUpdateUtils;}public void update(Context context, String appInfo, onUpdateListener mUpdateListener){String url = "https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk";String filePath = "/sdcard/download";download(context, url, filePath, mUpdateListener);}/*** 下载更新* @param context* @param url 下载地址* @param filePath 保存目录* @param mUpdateListener*/public void download(Context context, String url, String filePath, onUpdateListener mUpdateListener){Intent intent = new Intent(context, DownloadServices.class);intent.putExtra("url", url);intent.putExtra("file_path", filePath);context.startService(intent);} }
DownloadService.java
package com.cnziz.updatelib.download;import java.io.File; import java.io.IOException;import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log;import com.cnziz.updatelib.R; import com.cnziz.updatelib.utils.Listener.onUpdateListener; import com.cnziz.updatelib.utils.LogUtils;public class DownloadServices extends Service {private final static int DOWNLOAD_COMPLETE = -2;private final static int DOWNLOAD_FAIL = -1;// 自定义通知栏类MyNotification myNotification;String filePathString; // 下载文件绝对路径(包括文件名)// 通知栏跳转Intentprivate Intent updateIntent = null;private PendingIntent updatePendingIntent = null;DownFileThread downFileThread; // 自定义文件下载线程private onUpdateListener mUpdateListener;private Handler updateHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case DOWNLOAD_COMPLETE:// 点击安装PendingIntentUri uri = Uri.fromFile(downFileThread.getApkFile());Intent installIntent = new Intent(Intent.ACTION_VIEW);installIntent.setDataAndType(uri,"application/vnd.android.package-archive");installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(installIntent); // updatePendingIntent = PendingIntent.getActivity( // DownloadServices.this, 0, installIntent, 0); // myNotification.changeContentIntent(updatePendingIntent); // myNotification.notification.defaults = Notification.DEFAULT_SOUND;// 铃声提醒 // myNotification.changeNotificationText("下载完成,请点击安装!");// 停止服务// myNotification.removeNotification();stopSelf();break;case DOWNLOAD_FAIL:// 下载失败// myNotification.changeProgressStatus(DOWNLOAD_FAIL);myNotification.changeNotificationText("文件下载失败!");mUpdateListener.downloadFail();stopSelf();break;default: // 下载中LogUtils.e("service", "index" + msg.what);// myNotification.changeNotificationText(msg.what+"%");myNotification.changeProgressStatus(msg.what);}}};public DownloadServices() {// TODO Auto-generated constructor stub// mcontext=context;LogUtils.e("service", "DownloadServices1");}@Overridepublic void onCreate() {// TODO Auto-generated method stubLogUtils.e("service", "onCreate");super.onCreate();}@Overridepublic void onDestroy() {// TODO Auto-generated method stubLogUtils.e("service", "onDestroy");if (downFileThread != null)downFileThread.interuptThread(); // if (null != myNotification) { // myNotification.removeNotification(); // }stopSelf();super.onDestroy();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubLogUtils.e("service", "onStartCommand");String url = intent.getStringExtra("url");String filePath = intent.getStringExtra("file_path");mUpdateListener = (onUpdateListener) intent.getParcelableExtra("listener");// updateIntent = new Intent(this, MainActivity.class);// PendingIntent updatePendingIntent = PendingIntent.getActivity(this,// 0,// updateIntent, 0);myNotification = new MyNotification(this, updatePendingIntent, 1);// myNotification.showDefaultNotification(R.drawable.ic_launcher, "测试",// "开始下载");myNotification.showCustomizeNotification(R.drawable.ic_launcher,"测试下载", R.layout.notification);if (!filePath.endsWith("/")) {filePath = filePath +"/";}File path = new File(filePath);if (!path.exists()) {path.mkdir();}String[] s = url.split("/");filePathString = filePath + s[s.length-1];File file = new File(filePathString);if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}// 开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞downFileThread = new DownFileThread(updateHandler,url,filePathString);new Thread(downFileThread).start();return super.onStartCommand(intent, flags, startId);}@Override@Deprecatedpublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubLogUtils.e("service", "onStart");super.onStart(intent, startId);}@Overridepublic IBinder onBind(Intent arg0) {// TODO Auto-generated method stubLogUtils.e("service", "onBind");return null;}}下载线程 DownFileThread.java
package com.cnziz.updatelib.download;import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException;import com.cnziz.updatelib.utils.LogUtils;import android.annotation.SuppressLint; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.os.StrictMode; import android.util.Log;public class DownFileThread implements Runnable {public final static int DOWNLOAD_COMPLETE = -2;public final static int DOWNLOAD_FAIL = -1;public final static String TAG = "DownFileThread";Handler mHandler; // 传入的Handler,用于像Activity或service通知下载进度String urlStr; // 下载URLFile apkFile; // 文件保存路径boolean isFinished; // 下载是否完成boolean interupted = false; // 是否强制停止下载线程public DownFileThread(Handler handler, String urlStr, String filePath) {LogUtils.i(TAG, urlStr);this.mHandler = handler;this.urlStr = urlStr;apkFile = new File(filePath);isFinished = false;}public File getApkFile() {if (isFinished)return apkFile;elsereturn null;}public boolean isFinished() {return isFinished;}/*** 强行终止文件下载*/public void interuptThread() {interupted = true;}@SuppressLint("NewApi")@Overridepublic void run() {// TODO Auto-generated method stubif (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {java.net.URL url = null;HttpURLConnection conn = null;InputStream iStream = null;// if (DEVELOPER_MODE){StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork() // or .detectAll() for all// detectable problems.penaltyLog().build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());}try {url = new java.net.URL(urlStr);conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5 * 1000);conn.setReadTimeout(20 * 1000);iStream = conn.getInputStream();} catch (MalformedURLException e) {LogUtils.e(TAG, "MalformedURLException");e.printStackTrace();} catch (Exception e) {LogUtils.e(TAG, "获得输入流失败");e.printStackTrace();}FileOutputStream fos = null;try {fos = new FileOutputStream(apkFile);} catch (FileNotFoundException e) {LogUtils.i(TAG, "获得输出流失败:new FileOutputStream(apkFile);");e.printStackTrace();}BufferedInputStream bis = new BufferedInputStream(iStream);byte[] buffer = new byte[1024];int len;// 获取文件总长度int length = conn.getContentLength();double rate = (double) 100 / length; // 最大进度转化为100int timeLoad = length/100/1024;int total = 0;int times = 0;// 设置更新频率,频繁操作UI线程会导致系统奔溃try {LogUtils.e("threadStatus", "开始下载");while (false == interupted && ((len = bis.read(buffer)) != -1)) {fos.write(buffer, 0, len);// 获取已经读取长度total += len;int p = (int) (total * rate);// Log.e("num", rate + "," + total + "," + p);if (times >= timeLoad || p == 100) {/** 这是防止频繁地更新通知,而导致系统变慢甚至崩溃。 非常重要。。。。。*/LogUtils.e("time", String.valueOf(times));times = 0;Message msg = Message.obtain();msg.what = p;mHandler.sendMessage(msg);}times++;}fos.close();bis.close();iStream.close();if (total == length) {isFinished = true;mHandler.sendEmptyMessage(DOWNLOAD_COMPLETE);LogUtils.e(TAG, "下载完成结束");return;}LogUtils.e(TAG, "强制中途结束");// mhandler.sendEmptyMessage(4);} catch (IOException e) {LogUtils.e(TAG, "异常中途结束");mHandler.sendEmptyMessage(DOWNLOAD_FAIL);e.printStackTrace();}} else {LogUtils.e(TAG, "外部存储卡不存在,下载失败!");mHandler.sendEmptyMessage(DOWNLOAD_FAIL);}} }自定义通知 MyNotification.java package com.cnziz.updatelib.download;import com.cnziz.updatelib.R;import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.widget.RemoteViews;public class MyNotification {public final static int DOWNLOAD_COMPLETE = -2;public final static int DOWNLOAD_FAIL = -1;Context mContext; // Activity或Service上下文Notification notification; // notificationNotificationManager nm;String titleStr; // 通知标题String contentStr; // 通知内容PendingIntent contentIntent; // 点击通知后的动作int notificationID; // 通知的唯一标示IDint iconID; // 通知栏图标long when = System.currentTimeMillis();RemoteViews remoteView = null; // 自定义的通知栏视图/*** * @param context* Activity或Service上下文* @param contentIntent* 点击通知后的动作* @param id* 通知的唯一标示ID*/public MyNotification(Context context, PendingIntent contentIntent, int id) {// TODO Auto-generated constructor stubmContext = context;notificationID = id;this.contentIntent = contentIntent;this.nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);}/*** 显示自定义通知* * @param icoId* 自定义视图中的图片ID* @param titleStr* 通知栏标题* @param layoutId* 自定义布局文件ID*/public void showCustomizeNotification(int icoId, String titleStr,int layoutId) {this.titleStr = titleStr;notification = new Notification(R.drawable.ic_launcher, titleStr, when);notification.flags = Notification.FLAG_ONLY_ALERT_ONCE;notification.flags |= Notification.FLAG_AUTO_CANCEL;notification.contentIntent = this.contentIntent;// 1、创建一个自定义的消息布局 view.xml// 2、在程序代码中使用RemoteViews的方法来定义image和text。然后把RemoteViews对象传到contentView字段if (remoteView == null) {remoteView = new RemoteViews(mContext.getPackageName(), layoutId);remoteView.setImageViewResource(R.id.ivNotification, icoId);remoteView.setTextViewText(R.id.tvTitle, titleStr);remoteView.setTextViewText(R.id.tvTip, "开始下载");remoteView.setProgressBar(R.id.pbNotification, 100, 0, false);notification.contentView = remoteView;}nm.notify(notificationID, notification);}/*** 更改自定义布局文件中的进度条的值* * @param p* 进度值(0~100)*/public void changeProgressStatus(int p) {if (notification.contentView != null) {if (p == DOWNLOAD_FAIL)notification.contentView.setTextViewText(R.id.tvTip, "下载失败! ");else if (p == 100)notification.contentView.setTextViewText(R.id.tvTip,"下载完成,请点击安装");elsenotification.contentView.setTextViewText(R.id.tvTip, "进度(" + p+ "%)");notification.contentView.setProgressBar(R.id.pbNotification, 100,p, false);}nm.notify(notificationID, notification);}public void changeContentIntent(PendingIntent intent) {this.contentIntent = intent;notification.contentIntent = intent;}/*** 显示系统默认格式通知* * @param iconId* 通知栏图标ID* @param titleText* 通知栏标题* @param contentStr* 通知栏内容*/public void showDefaultNotification(int iconId, String titleText,String contentStr) {this.titleStr = titleText;this.contentStr = contentStr;this.iconID = iconId;notification = new Notification();notification.tickerText = titleStr;notification.icon = iconID;notification.flags = Notification.FLAG_INSISTENT;notification.flags |= Notification.FLAG_AUTO_CANCEL;notification.contentIntent = this.contentIntent;// 添加声音效果// notification.defaults |= Notification.DEFAULT_SOUND;// 添加震动,后来得知需要添加震动权限 : Virbate Permission// mNotification.defaults |= Notification.DEFAULT_VIBRATE ;// 添加状态标志// FLAG_AUTO_CANCEL 该通知能被状态栏的清除按钮给清除掉// FLAG_NO_CLEAR 该通知能被状态栏的清除按钮给清除掉// FLAG_ONGOING_EVENT 通知放置在正在运行// FLAG_INSISTENT 通知的音乐效果一直播放notification.flags = Notification.FLAG_ONLY_ALERT_ONCE;changeNotificationText(contentStr);}/*** 改变默认通知栏的通知内容* * @param content*/public void changeNotificationText(String content) {notification.setLatestEventInfo(mContext, titleStr, content,contentIntent);// 设置setLatestEventInfo方法,如果不设置会App报错异常// NotificationManager mNotificationManager = (NotificationManager)// getSystemService(Context.NOTIFICATION_SERVICE);// 注册此通知// 如果该NOTIFICATION_ID的通知已存在,会显示最新通知的相关信息 ,比如tickerText 等nm.notify(notificationID, notification);}/*** 移除通知*/public void removeNotification() {// 取消的只是当前Context的Notificationnm.cancel(notificationID);} }
主要代码都在这了,下面是完整的项目链接
https://github.com/yan1348/ServiceDownLoad
总结
以上是生活随笔为你收集整理的Android Service下载文件并自定义通知提示下载的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: service和thread的区别,何时
- 下一篇: Android Service完全解析,