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的区别,何时
- 下一篇: Service和Thread的关系