Android DownloadManager 文件下载 带进度按钮 和通知栏同步
2016-04-12 14:16
543 查看
琢磨DownloadManager下载文件的时候发现的,正好整理一下,现在文件下载是每个apk必备功能,更行是肯定的.
话不多说,看效果:
ps:网上随便找的一个小apk.
主要核心类两个,一个MainActivity,一个帮助DownloadManagerHelp,
MainActivity代码:
DownloadManagerHelp 代码:
备注一下:
图中,两次下载,第一次只是看效果,没什么实际逻辑;第二次才是链接网络;
代码里面注释说明要加的地方有点多,以后会慢慢补上.
demo下载地址 ps:有分的赏个分场,没分的赏个人场
此处附个git大婶的链接 ,就是用他的三方库: 点击打开
我的demo是eclipse完成的,三方效果库里面有lib源码,如果是Android studio 开发,可以直接在build.gradle添加三方库的支持 :
之后会附加个百度云的demo地址.有空再补,下班!
话不多说,看效果:
ps:网上随便找的一个小apk.
主要核心类两个,一个MainActivity,一个帮助DownloadManagerHelp,
MainActivity代码:
package com.tyxo.downloadmanager; import java.io.File; import java.text.DecimalFormat; import android.app.DownloadManager; import android.app.DownloadManager.Query; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.tyxo.downloadmanager.DownloadManagerHelp; import com.tyxo.downloadmanager.PreferencesUtils; import com.tyxo.lib_processbutton.iml.SubmitProcessButton; /** * DownloadManagerDemo */ public class MainActivity extends BaseActivity { public static final String DOWNLOAD_FILE_NAME = "Tyxo.apk"; public static final String APK_URL = "http://125.39.109.30/apk.r1.market.hiapk.com/data/upload/apkres/2016/4_5/16/com.hiapk.live_044405.apk"; // http://125.39.109.30/apk.r1.market.hiapk.com/data/upload/apkres/2016/4_5/16/com.hiapk.live_044405.apk?wsiphost=local public static final String KEY_NAME_DOWNLOAD_ID = "downloadId"; private Button downloadButton; private ProgressBar downloadProgress; private TextView downloadTip; private TextView downloadSize; private TextView downloadPrecent; private Button downloadCancel; private DownloadManager downloadManager; private DownloadManagerHelp downloadManagerPro; private long downloadId = 0; private MyHandler handler; private DownloadChangeObserver downloadObserver; private CompleteReceiver completeReceiver; private SubmitProcessButton btn_SubmitProcessButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState, R.layout.download_manager_demo); handler = new MyHandler(); downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE); downloadManagerPro = new DownloadManagerHelp(downloadManager); // see android mainfest.xml, accept minetype of cn.trinea.download.file Intent intent = getIntent(); if (intent != null) { Uri data = intent.getData(); if (data != null) { Toast.makeText(context, data.toString(), Toast.LENGTH_LONG).show(); } } initView(); initData(); downloadObserver = new DownloadChangeObserver(); completeReceiver = new CompleteReceiver(); /** register download success broadcast **/ registerReceiver(completeReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); } @Override protected void onResume() { super.onResume(); /** observer download change **/ getContentResolver().registerContentObserver(DownloadManagerHelp.CONTENT_URI, true, downloadObserver); updateView(); } @Override protected void onPause() { super.onPause(); getContentResolver().unregisterContentObserver(downloadObserver); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(completeReceiver); } private void initView() { btn_SubmitProcessButton = (SubmitProcessButton) findViewById(R.id.btn_SubmitProcessButton); downloadButton = (Button)findViewById(R.id.download_button); downloadCancel = (Button)findViewById(R.id.download_cancel); downloadProgress = (ProgressBar)findViewById(R.id.download_progress); downloadTip = (TextView)findViewById(R.id.download_tip); downloadTip.setText(getString(R.string.tip_download_file) + Environment.getExternalStoragePublicDirectory("tyxo")); downloadSize = (TextView)findViewById(R.id.download_size); downloadPrecent = (TextView)findViewById(R.id.download_precent); } private int mProgress; final Handler HandlerSub = new Handler(); private Runnable runnable = new Runnable() { @Override public void run() { mProgress += 10; btn_SubmitProcessButton.setProgress(mProgress); if (mProgress < 100) { HandlerSub.postDelayed(this, 200); } else { Toast.makeText(getApplicationContext(), "下载完成", 0).show(); } } }; private void initData() { btn_SubmitProcessButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { HandlerSub.postDelayed(runnable, 500); btn_SubmitProcessButton.setEnabled(false); } }); /** * get download id from preferences.<br/> * if download id bigger than 0, means it has been downloaded, then query status and show right text; */ downloadId = PreferencesUtils.getLong(context, KEY_NAME_DOWNLOAD_ID); updateView(); downloadButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { File folder = Environment.getExternalStoragePublicDirectory("tyxo"); if (!folder.exists() || !folder.isDirectory()) { folder.mkdirs(); } DownloadManager.Request request = new DownloadManager.Request(Uri.parse(APK_URL)); // request.setDestinationInExternalPublicDir(DOWNLOAD_FOLDER_NAME, DOWNLOAD_FILE_NAME); // 此方法,有的手机装TF卡,会蹦 request.setDestinationInExternalFilesDir(context, "tyxo", DOWNLOAD_FILE_NAME); request.setTitle(getString(R.string.download_notification_title)); request.setDescription("some desc"); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setVisibleInDownloadsUi(false); // request.allowScanningByMediaScanner(); // request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); // request.setShowRunningNotification(false); // request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); request.setMimeType("application/cn.tyxo.download.file"); downloadId = downloadManager.enqueue(request); // save download id to preferences PreferencesUtils.putLong(context, KEY_NAME_DOWNLOAD_ID, downloadId); updateView(); } }); downloadCancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { downloadManager.remove(downloadId); updateView(); } }); } /** * install app */ public static boolean install(Context context, String filePath) { Intent i = new Intent(Intent.ACTION_VIEW); File file = new File(filePath); if (file != null && file.length() > 0 && file.exists() && file.isFile()) { i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive"); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); return true; } return false; } class DownloadChangeObserver extends ContentObserver { public DownloadChangeObserver() { super(handler); } @Override public void onChange(boolean selfChange) { updateView(); } } // 下载完成,自动弹出安装 class CompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { /** * get the id of download which have download success, if the id is my id and it's status is successful, * then install it **/ String action = intent.getAction(); long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); long downloadID = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); String apkFilePath = querySavePath(downloadID,downloadManager); if (completeDownloadId == downloadId) { initData(); updateView(); // if download successful, install apk /*if (downloadManagerPro.getStatusById(downloadId) == DownloadManager.STATUS_SUCCESSFUL) { String apkFilePath = new StringBuilder(Environment.getExternalStorageDirectory().getAbsolutePath()) .append(File.separator).append("tyxo").append(File.separator) .append(DOWNLOAD_FILE_NAME).toString(); install(context, apkFilePath); }*/ if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { installAPK(apkFilePath); } } } }; private void installAPK(String apkFilePath){ if (!TextUtils.isEmpty(apkFilePath)) { Uri uri = Uri.parse(apkFilePath); File file = new File(uri.getPath()); if (file.exists()) { Intent i = new Intent(Intent.ACTION_VIEW); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.setDataAndType(uri, "application/vnd.android.package-archive"); context.startActivity(i); } } } /** * 根据下载ID查询下载文件保存的路径 * @param @param downloadManager * @return */ public static String querySavePath(long downloadID, DownloadManager downloadManager) { String savePath = ""; Query query = new Query(); query.setFilterById(downloadID); Cursor c = downloadManager.query(query); if (c.moveToFirst()) { int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS); if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) { savePath = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); } } c.close(); return savePath; } // 发消息,更新UI视图 public void updateView() { int[] bytesAndStatus = downloadManagerPro.getBytesAndStatus(downloadId); handler.sendMessage(handler.obtainMessage(0, bytesAndStatus[0], bytesAndStatus[1], bytesAndStatus[2])); } // 处理消息,更新UI视图 private class MyHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: int status = (Integer)msg.obj; if (isDownloading(status)) { downloadProgress.setVisibility(View.VISIBLE); downloadProgress.setMax(0); downloadProgress.setProgress(0); btn_SubmitProcessButton.setProgress(0); downloadButton.setVisibility(View.GONE); downloadSize.setVisibility(View.VISIBLE); downloadPrecent.setVisibility(View.VISIBLE); downloadCancel.setVisibility(View.VISIBLE); if (msg.arg2 < 0) { downloadProgress.setIndeterminate(true); downloadPrecent.setText("0%"); downloadSize.setText("0M/0M"); } else { downloadProgress.setIndeterminate(false); downloadProgress.setMax(msg.arg2); downloadProgress.setProgress(msg.arg1); btn_SubmitProcessButton.setProgress(switchPercent(msg.arg1, msg.arg2)); downloadPrecent.setText(getNotiPercent(msg.arg1, msg.arg2)); downloadSize.setText(getAppSize(msg.arg1) + "/" + getAppSize(msg.arg2)); } } else { downloadProgress.setVisibility(View.GONE); downloadProgress.setMax(0); downloadProgress.setProgress(0); btn_SubmitProcessButton.setProgress(0); downloadButton.setVisibility(View.VISIBLE); downloadSize.setVisibility(View.GONE); downloadPrecent.setVisibility(View.GONE); downloadCancel.setVisibility(View.GONE); if (status == DownloadManager.STATUS_FAILED) { downloadButton.setText(getString(R.string.app_status_download_fail)); } else if (status == DownloadManager.STATUS_SUCCESSFUL) { downloadButton.setText(getString(R.string.app_status_downloaded)); } else { downloadButton.setText(getString(R.string.app_status_download)); } } break; } } } public int switchPercent(long progress, long max) { int rate = 0; if (progress <= 0 || max <= 0) { rate = 0; } else if (progress > max) { rate = 100; } else { rate = (int)((double)progress / max * 100); } if(rate>98){ return rate; }else { return rate + 1; } } static final DecimalFormat DOUBLE_DECIMAL_FORMAT = new DecimalFormat("0.##"); public static final int MB_2_BYTE = 1024 * 1024; public static final int KB_2_BYTE = 1024; /** * @param size */ public static CharSequence getAppSize(long size) { if (size <= 0) { return "0M"; } if (size >= MB_2_BYTE) { return new StringBuilder(16).append(DOUBLE_DECIMAL_FORMAT.format((double)size / MB_2_BYTE)).append("M"); } else if (size >= KB_2_BYTE) { return new StringBuilder(16).append(DOUBLE_DECIMAL_FORMAT.format((double)size / KB_2_BYTE)).append("K"); } else { return size + "B"; } } public static String getNotiPercent(long progress, long max) { int rate = 0; if (progress <= 0 || max <= 0) { rate = 0; } else if (progress > max) { rate = 100; } else { rate = (int)((double)progress / max * 100); } return new StringBuilder(16).append(rate).append("%").toString(); } public static boolean isDownloading(int downloadManagerStatus) { return downloadManagerStatus == DownloadManager.STATUS_RUNNING || downloadManagerStatus == DownloadManager.STATUS_PAUSED || downloadManagerStatus == DownloadManager.STATUS_PENDING; } }
DownloadManagerHelp 代码:
package com.tyxo.downloadmanager; import java.lang.reflect.Method; import android.app.DownloadManager; import android.app.DownloadManager.Request; import android.database.Cursor; import android.net.Uri; import android.os.Build; /** * DownloadManagerPro */ public class DownloadManagerHelp { public static final Uri CONTENT_URI = Uri.parse("content://downloads/my_downloads"); /** represents downloaded file above api 11 **/ public static final String COLUMN_LOCAL_FILENAME = "local_filename"; /** represents downloaded file below api 11 **/ public static final String COLUMN_LOCAL_URI = "local_uri"; public static final String METHOD_NAME_PAUSE_DOWNLOAD = "pauseDownload"; public static final String METHOD_NAME_RESUME_DOWNLOAD = "resumeDownload"; private static boolean isInitPauseDownload = false; private static boolean isInitResumeDownload = false; private static Method pauseDownload = null; private static Method resumeDownload = null; private DownloadManager downloadManager; public DownloadManagerHelp(DownloadManager downloadManager) { this.downloadManager = downloadManager; } /** * get download status * * @param downloadId * @return */ public int getStatusById(long downloadId) { return getInt(downloadId, DownloadManager.COLUMN_STATUS); } /** * get downloaded byte, total byte * * @param downloadId * @return a int array with two elements * <ul> * <li>result[0] represents downloaded bytes, This will initially be -1.</li> * <li>result[1] represents total bytes, This will initially be -1.</li> * </ul> */ public int[] getDownloadBytes(long downloadId) { int[] bytesAndStatus = getBytesAndStatus(downloadId); return new int[] {bytesAndStatus[0], bytesAndStatus[1]}; } /** * get downloaded byte, total byte and download status * * @param downloadId * @return a int array with three elements * <ul> * <li>result[0] represents downloaded bytes, This will initially be -1.</li> * <li>result[1] represents total bytes, This will initially be -1.</li> * <li>result[2] represents download status, This will initially be 0.</li> * </ul> */ public int[] getBytesAndStatus(long downloadId) { int[] bytesAndStatus = new int[] {-1, -1, 0}; DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId); Cursor c = null; try { c = downloadManager.query(query); if (c != null && c.moveToFirst()) { bytesAndStatus[0] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); bytesAndStatus[1] = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); bytesAndStatus[2] = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); } } finally { if (c != null) { c.close(); } } return bytesAndStatus; } /** * pause download * * @param ids the IDs of the downloads to be paused * @return the number of downloads actually paused, -1 if exception or method not exist */ public int pauseDownload(long... ids) { initPauseMethod(); if (pauseDownload == null) { return -1; } try { return ((Integer)pauseDownload.invoke(downloadManager, ids)).intValue(); } catch (Exception e) { /** * accept all exception, include ClassNotFoundException, NoSuchMethodException, InvocationTargetException, * NullPointException */ e.printStackTrace(); } return -1; } /** * resume download * * @param ids the IDs of the downloads to be resumed * @return the number of downloads actually resumed, -1 if exception or method not exist */ public int resumeDownload(long... ids) { initResumeMethod(); if (resumeDownload == null) { return -1; } try { return ((Integer)resumeDownload.invoke(downloadManager, ids)).intValue(); } catch (Exception e) { /** * accept all exception, include ClassNotFoundException, NoSuchMethodException, InvocationTargetException, * NullPointException */ e.printStackTrace(); } return -1; } /** * whether exist pauseDownload and resumeDownload method in {@link DownloadManager} * * @return */ public static boolean isExistPauseAndResumeMethod() { initPauseMethod(); initResumeMethod(); return pauseDownload != null && resumeDownload != null; } private static void initPauseMethod() { if (isInitPauseDownload) { return; } isInitPauseDownload = true; try { pauseDownload = DownloadManager.class.getMethod(METHOD_NAME_PAUSE_DOWNLOAD, long[].class); } catch (Exception e) { // accept all exception e.printStackTrace(); } } private static void initResumeMethod() { if (isInitResumeDownload) { return; } isInitResumeDownload = true; try { resumeDownload = DownloadManager.class.getMethod(METHOD_NAME_RESUME_DOWNLOAD, long[].class); } catch (Exception e) { // accept all exception e.printStackTrace(); } } /** * get download file name * * @param downloadId * @return */ public String getFileName(long downloadId) { return getString(downloadId, (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ? COLUMN_LOCAL_URI : COLUMN_LOCAL_FILENAME)); } /** * get download uri * * @param downloadId * @return */ public String getUri(long downloadId) { return getString(downloadId, DownloadManager.COLUMN_URI); } /** * get failed code or paused reason * * @param downloadId * @return <ul> * <li>if status of downloadId is {@link DownloadManager#STATUS_PAUSED}, return * {@link #getPausedReason(long)}</li> * <li>if status of downloadId is {@link DownloadManager#STATUS_FAILED}, return {@link #getErrorCode(long)}</li> * <li>if status of downloadId is neither {@link DownloadManager#STATUS_PAUSED} nor * {@link DownloadManager#STATUS_FAILED}, return 0</li> * </ul> */ public int getReason(long downloadId) { return getInt(downloadId, DownloadManager.COLUMN_REASON); } /** * get paused reason * * @param downloadId * @return <ul> * <li>if status of downloadId is {@link DownloadManager#STATUS_PAUSED}, return one of * {@link DownloadManager#PAUSED_WAITING_TO_RETRY}<br/> * {@link DownloadManager#PAUSED_WAITING_FOR_NETWORK}<br/> * {@link DownloadManager#PAUSED_QUEUED_FOR_WIFI}<br/> * {@link DownloadManager#PAUSED_UNKNOWN}</li> * <li>else return {@link DownloadManager#PAUSED_UNKNOWN}</li> * </ul> */ public int getPausedReason(long downloadId) { return getInt(downloadId, DownloadManager.COLUMN_REASON); } /** * get failed error code * * @param downloadId * @return one of {@link DownloadManager#ERROR_*} */ public int getErrorCode(long downloadId) { return getInt(downloadId, DownloadManager.COLUMN_REASON); } public static class RequestPro extends DownloadManager.Request { public static final String METHOD_NAME_SET_NOTI_CLASS = "setNotiClass"; public static final String METHOD_NAME_SET_NOTI_EXTRAS = "setNotiExtras"; private static boolean isInitNotiClass = false; private static boolean isInitNotiExtras = false; private static Method setNotiClass = null; private static Method setNotiExtras = null; /** * @param uri the HTTP URI to download. */ public RequestPro(Uri uri) { super(uri); } /** * set noti class, only init once * * @param className full class name */ public void setNotiClass(String className) { synchronized (this) { if (!isInitNotiClass) { isInitNotiClass = true; try { setNotiClass = Request.class.getMethod(METHOD_NAME_SET_NOTI_CLASS, CharSequence.class); } catch (Exception e) { // accept all exception e.printStackTrace(); } } } if (setNotiClass != null) { try { setNotiClass.invoke(this, className); } catch (Exception e) { /** * accept all exception, include ClassNotFoundException, NoSuchMethodException, * InvocationTargetException, NullPointException */ e.printStackTrace(); } } } /** * set noti extras, only init once * * @param extras */ public void setNotiExtras(String extras) { synchronized (this) { if (!isInitNotiExtras) { isInitNotiExtras = true; try { setNotiExtras = Request.class.getMethod(METHOD_NAME_SET_NOTI_EXTRAS, CharSequence.class); } catch (Exception e) { // accept all exception e.printStackTrace(); } } } if (setNotiExtras != null) { try { setNotiExtras.invoke(this, extras); } catch (Exception e) { /** * accept all exception, include ClassNotFoundException, NoSuchMethodException, * InvocationTargetException, NullPointException */ e.printStackTrace(); } } } } /** * get string column * * @param downloadId * @param columnName * @return */ private String getString(long downloadId, String columnName) { DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId); String result = null; Cursor c = null; try { c = downloadManager.query(query); if (c != null && c.moveToFirst()) { result = c.getString(c.getColumnIndex(columnName)); } } finally { if (c != null) { c.close(); } } return result; } /** * get int column * * @param downloadId * @param columnName * @return */ private int getInt(long downloadId, String columnName) { DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId); int result = -1; Cursor c = null; try { c = downloadManager.query(query); if (c != null && c.moveToFirst()) { result = c.getInt(c.getColumnIndex(columnName)); } } finally { if (c != null) { c.close(); } } return result; } }
备注一下:
图中,两次下载,第一次只是看效果,没什么实际逻辑;第二次才是链接网络;
代码里面注释说明要加的地方有点多,以后会慢慢补上.
demo下载地址 ps:有分的赏个分场,没分的赏个人场
此处附个git大婶的链接 ,就是用他的三方库: 点击打开
我的demo是eclipse完成的,三方效果库里面有lib源码,如果是Android studio 开发,可以直接在build.gradle添加三方库的支持 :
dependencies { compile 'com.github.dmytrodanylyk.android-process-button:library:1.0.4' }
之后会附加个百度云的demo地址.有空再补,下班!
相关文章推荐
- Android gradle简介
- android(NDK+JNI)---Android JNI开发生成.h头文件问题
- android shape的使用
- Android动画--逐帧动画和补间动画简单介绍和基本用法(一)
- Android插件化开发-hook动态代理
- 使用Android studio分析内存泄露
- android soundpool的使用
- Android进阶2之图片缩略图(解决大图片溢出问题)
- 浅谈Android应用保护(零):出发点和背景
- Android 代码混淆总结
- android 自定义含有滚动选择器的对话框
- Android:SingleTask对Intent传递数据的影响及解决办法
- Android中屏幕的方向
- 【转】Android手机分辨率基础知识(DPI,DIP计算)
- Android:SpannableString使用详解
- Android_自定义ViewPager指示器
- Android ViewPager使用详解
- Android性能优化总结
- Android-BaiduMapSDK示例的key验证失败问题
- Android finish 无法退出当前Activity