DownLoadManager的下载及进度监听

  • 简介:
    DownLoadManager是一个系统服务,用于处理长时间下载任务,DownLoadManager会在后台处理HTTP交互和重试下载失败或跨连接启动系统,DownloadManager是用service更新进度,用广播监听下载完成和点击事件。DownLoadManager中有两个内部类:DownloadManager.Query和DownloadManager.Request。前者用于查询下载,后者用于设置一些效果设置。

  • DownloadManager.Request类的常用方法:

    addRequestHeader(String header, String value):添加一个请求头
    setAllowedNetworkTypes(int flags):设置下载时所使用的网络类型,提供的常量有:NETWORK_BLUETOOTH、NETWORK_MOBILE、NETWORK_WIFI。
    setAllowedOverRoaming(boolean allowed):是否允许漫游
    setDescription(CharSequence description):设置下载的描述信息
    setDestinationInExternalFilesDir(Context context, String dirType, String subPath):设置下载文件外部存储目录
    setDestinationUri(Uri uri):设置下载目标的URI
    setMimeType(String mimeType):设置MIME类型
    setShowRunningNotification(boolean show):设置是否显示下载进度提示
    setTitle(CharSequence title):设置下载时Notification的标题
    setVisibleInDownloadsUi(boolean isVisible):设置是否现在下载界面
    以上的各个方法,如果不设置的话就是默认的。

  • 有关暂停的一些状态,同样COLUMN_REASON字段的值定义常量有:

    int PAUSED_QUEUED_FOR_WIFI 由于移动网络数据问题,等待WiFi连接能用后再重新进入下载队列
    int PAUSED_UNKNOWN 未知原因导致了任务下载的暂停
    int PAUSED_WAITING_FOR_NETWORK 可能由于没有网络连接而无法下载,等待有可用的网络连接恢复
    int PAUSED_WAITING_TO_RETRY 由于重重原因导致下载暂停,等待重试

  • DownloadManager.Query类
      DownloadManager.Query类只有两个方法:setFilterById(long… ids)根据任务Id查找和setFilterByStatus(int flags) 根据任务状态查找。但是定义了很多常量:

    下载状态常量:

    int STATUS_FAILED 失败
    int STATUS_PAUSED 暂停
    int STATUS_PENDING 等待将开始
    int STATUS_RUNNING 正在处理中
    int STATUS_SUCCESSFUL 已经下载成功
    DownloadManager.Query类查询返回的是一个Cursor游标,上面描述的状态就会保存在COLUMN_STATUS 字段中。下载状态会以广播的形式通知,Android系统定义的Action有:
    ACTION_DOWNLOAD_COMPLETE下载完成的动作。
    ACTION_NOTIFICATION_CLICKED 当用户单击notification中下载管理的某项时触发。
    ACTION_VIEW_DOWNLOADS 查看下载项
    对于未完成的状态,我们查找COLUMN_REASON字段,定义的常量有:
    int ERROR_CANNOT_RESUME 不能够继续,由于一些其他原因。
    int ERROR_DEVICE_NOT_FOUND 外部存储设备没有找到,比如SD卡没有插入。
    int ERROR_FILE_ALREADY_EXISTS 要下载的文件已经存在了,要想重新下载需要删除原来的文件
    int ERROR_FILE_ERROR 可能由于SD卡原因导致了文件错误。
    int ERROR_HTTP_DATA_ERROR 在Http传输过程中出现了问题。
    int ERROR_INSUFFICIENT_SPACE 由于SD卡空间不足造成的
    int ERROR_TOO_MANY_REDIRECTS 这个Http有太多的重定向,导致无法正常下载
    int ERROR_UNHANDLED_HTTP_CODE 无法获取http出错的原因,比如说远程服务器没有响应。
    int ERROR_UNKNOWN 未知的错误类型.

  • 有关暂停的一些状态,同样COLUMN_REASON字段的值定义常量有:

    int PAUSED_QUEUED_FOR_WIFI 由于移动网络数据问题,等待WiFi连接能用后再重新进入下载队列
    int PAUSED_UNKNOWN 未知原因导致了任务下载的暂停
    int PAUSED_WAITING_FOR_NETWORK 可能由于没有网络连接而无法下载,等待有可用的网络连接恢复
    int PAUSED_WAITING_TO_RETRY 由于重重原因导致下载暂停,等待重试

  • DownLoadManager的下载及进度监听例子:
    service工具类如下:

public class DownloadServise extends Service {
   private static final String TAG = DownloadServise.class.getSimpleName();

   public static final int HANDLE_DOWNLOAD = 0x001;
   public static final String BUNDLE_KEY_DOWNLOAD_URL = "download_url";
   public static final float UNBIND_SERVICE = 2.0F;

   private Activity activity;
   private DownloadBinder binder;
   private DownloadManager downloadManager;
   private DownloadChangeObserver downloadObserver;
   private BroadcastReceiver downLoadBroadcast;
   private ScheduledExecutorService scheduledExecutorService;

   //下载任务ID
   private long downloadId;
   private String downloadUrl;
   public static OnProgressListener onProgressListener;

   @SuppressLint("HandlerLeak") public Handler downLoadHandler = new Handler() { //主线程的handler
       @Override
       public void handleMessage(Message msg) {
           super.handleMessage(msg);
           if (onProgressListener != null && HANDLE_DOWNLOAD == msg.what) {
               //被除数可以为0,除数必须大于0
               if (msg.arg1 >= 0 && msg.arg2 > 0) {
                   onProgressListener.onProgress(msg.arg1 / (float) msg.arg2);
               }
           }
       }
   };

   private Runnable progressRunnable = new Runnable() {
       @Override
       public void run() {
           updateProgress();
       }
   };

   @Override
   public void onCreate() {
       super.onCreate();
       binder = new DownloadBinder();
   }

   @Override
   public IBinder onBind(Intent intent) {
       downloadUrl = intent.getStringExtra(BUNDLE_KEY_DOWNLOAD_URL);
       downloadApk(downloadUrl);
       return binder;
   }

   /**
    * 下载最新APK
    */
   private void downloadApk(String url) {
       downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
       downloadObserver = new DownloadChangeObserver();

       registerContentObserver();

       DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
       DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
       //request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "my.apk");
       request.setDestinationInExternalFilesDir(this, null, "my.apk");
       request.setTitle("title");
       //request.setDescription("下载中通知栏提示");
       request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
       request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
       //request.setMimeType("application/cn.trinea.download.file"); //用于响应点击的打开文件
       request.setVisibleInDownloadsUi(true);  //显示下载界面
       request.allowScanningByMediaScanner();  //准许被系统扫描到
       downloadId = downloadManager.enqueue(request);
       registerBroadcast(); //下载成功和点击通知栏动作监听
   }

   /**
    * 注册广播
    */
   private void registerBroadcast() {
       /**注册service 广播 1.任务完成时 2.进行中的任务被点击*/
       IntentFilter intentFilter = new IntentFilter();
       intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
       intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
       registerReceiver(downLoadBroadcast = new DownLoadBroadcast(), intentFilter);
   }

   /**
    * 注销广播
    */
   private void unregisterBroadcast() {
       if (downLoadBroadcast != null) {
           unregisterReceiver(downLoadBroadcast);
           downLoadBroadcast = null;
       }
   }

   /**
    * 注册ContentObserver
    */
   private void registerContentObserver() {
       /** observer download change **/
       if (downloadObserver != null) {
           getContentResolver().registerContentObserver(
               Uri.parse("content://downloads/my_downloads"), false, downloadObserver);
       }
   }

   /**
    * 注销ContentObserver
    */
   private void unregisterContentObserver() {
       if (downloadObserver != null) {
           getContentResolver().unregisterContentObserver(downloadObserver);
       }
   }

   /**
    * 关闭定时器,线程等操作
    */
   private void close() {
       if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
           scheduledExecutorService.shutdown();
       }

       if (downLoadHandler != null) {
           downLoadHandler.removeCallbacksAndMessages(null);
       }
   }

   /**
    * 发送Handler消息更新进度和状态
    * 将查询结果从子线程中发往主线程(handler方式),以防止ANR
    */
   private void updateProgress() {
       int[] bytesAndStatus = getBytesAndStatus(downloadId);
       downLoadHandler.sendMessage(downLoadHandler.obtainMessage(HANDLE_DOWNLOAD, bytesAndStatus[0], bytesAndStatus[1], bytesAndStatus[2]));
   }

   /**
    * 通过query查询下载状态,包括已下载数据大小,总大小,下载状态
    *
    * @param downloadId
    * @return
    */
   private int[] getBytesAndStatus(long downloadId) {
       int[] bytesAndStatus = new int[]{
               -1, -1, 0
       };
       DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
       Cursor cursor = null;
       try {
           cursor = downloadManager.query(query);
           if (cursor != null && cursor.moveToFirst()) {
               //已经下载文件大小
               bytesAndStatus[0] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
               //下载文件的总大小
               bytesAndStatus[1] = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
               //下载状态
               bytesAndStatus[2] = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
           }
       } finally {
           if (cursor != null) {
               cursor.close();
           }
       }
       return bytesAndStatus;
   }

   /**
    * 绑定此DownloadService的Activity实例
    *
    * @param activity
    */
   public void setTargetActivity(Activity activity) {
       this.activity = activity;
   }

   /**
    * 接受下载完成广播
    */
   private class DownLoadBroadcast extends BroadcastReceiver {

       @Override
       public void onReceive(Context context, Intent intent) {
           long downId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
           switch (intent.getAction()) {
               case DownloadManager.ACTION_DOWNLOAD_COMPLETE:
                   if (downloadId == downId && downId != -1 && downloadManager != null) {
                       Uri downIdUri = downloadManager.getUriForDownloadedFile(downloadId);

                       close();

                       if (downIdUri != null) {
                           SPTools.put(Constant.SP_DOWNLOAD_PATH, downIdUri.getPath());
                           LogUtil.showLog(TAG, "广播监听下载完成,APK存储路径为 :" + downIdUri.getPath());
                           installApk(context, downIdUri);
                       }
                       if (onProgressListener != null) {
                           onProgressListener.onProgress(UNBIND_SERVICE);
                       }
                   }
                   break;

               case DownloadManager.ACTION_NOTIFICATION_CLICKED:
                   ToastUitl.showToast("我被点击啦!");
                   break;
           }
       }
   }

   /**
    * 监听下载进度
    */
   private class DownloadChangeObserver extends ContentObserver {

       public DownloadChangeObserver() {
           super(downLoadHandler);
           scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
       }

       /**
        * 当所监听的Uri发生改变时,就会回调此方法
        * @param selfChange 此值意义不大, 一般情况下该回调值false
        */
       @Override
       public void onChange(boolean selfChange) {
           scheduledExecutorService.scheduleAtFixedRate(progressRunnable, 0, 1, TimeUnit.SECONDS); //在子线程中查询
       }
   }

   public class DownloadBinder extends Binder {
       /**
        * 返回当前服务的实例
        * @return
        */
       public DownloadServise getService() {
           return DownloadServise.this;
       }

   }

   public interface OnProgressListener {
       /**
        * 下载进度
        * @param fraction 已下载/总大小
        */
       void onProgress(float fraction);
   }

   /**
    * 对外开发的方法
    * @param onProgressListener
    */
   public void setOnProgressListener(OnProgressListener onProgressListener) {
       DownloadServise.onProgressListener = onProgressListener;
   }

   public static void installApk(Context context, Uri apkPath) {
       Intent intent = new Intent();
       intent.setAction(Intent.ACTION_VIEW);
       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       intent.setDataAndType(apkPath, "application/vnd.android.package-archive");
       context.startActivity(intent);
   }

   @Override
   public void onDestroy() {
       super.onDestroy();
       unregisterBroadcast();
       unregisterContentObserver();
   }
}

绑定服务开始下载代码:

private ProgressDialog progress;
 private boolean isBindService;
 private ServiceConnection conn = new ServiceConnection() { //通过ServiceConnection间接可以拿到某项服务对象

   @Override
   public void onServiceConnected(ComponentName name, IBinder service) {
     DownloadServise.DownloadBinder binder = (DownloadServise.DownloadBinder) service;
     DownloadServise downloadServise = binder.getService();

     //接口回调,下载进度
     downloadServise.setOnProgressListener(new DownloadServise.OnProgressListener() {
       @Override
       public void onProgress(float fraction) {
         progress.setProgress((int)(fraction * 100));

         //判断是否真的下载完成进行安装了,以及是否注册绑定过服务
         if (fraction == downloadServise.UNBIND_SERVICE && isBindService) {
           progress.setProgress(100);
           progress.dismiss();
           unbindService(conn);
           isBindService = false;
         }
       }
     });
   }

   @Override
   public void onServiceDisconnected(ComponentName name) {

   }
 };

 private void initProgressBar() {
   progress = new ProgressDialog(this);
   progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
   progress.setProgress(1);
   progress.setCancelable(false);
   progress.setCanceledOnTouchOutside(false);
   progress.show();
 }

private void downLoadCs() {  //下载调用
   initProgressBar();
   removeOldApk();
   Intent intent = new Intent(this, DownloadServise.class);
   intent.putExtra(DownloadServise.BUNDLE_KEY_DOWNLOAD_URL, "http://imtt.dd.qq.com/16891/3804D823FD7A0710F664D0126841BD10.apk?fsname=com.cxtx.chefu.app_1.3.0_39.apk&csr=1bbd");
   isBindService = bindService(intent, conn, BIND_AUTO_CREATE); //绑定服务即开始下载 调用onBind()
 }

 /**
  * 删除上次更新存储在本地的apk
  */
 private void removeOldApk() {
   //获取老APK的存储路径
   File fileName = new File(SPTools.getString(Constant.SP_DOWNLOAD_PATH, ""));

   if (fileName != null && fileName.exists() && fileName.isFile()) {
     fileName.delete();
   }
 }

最后别忘了在AndroidManifest.xml中声明:

其他参考:
网址1:http://www.jianshu.com/p/bb4cde6e88c6
网址2:http://blog.csdn.net/a907763895/article/details/12753149
Demo1: https://github.com/GitPhoenix/DownloadManager

.

你可能感兴趣的:(DownLoadManager的下载及进度监听)