原始完成于:2014-10-24 20:01:03

DownloadManager是一个处理HTTP下载请求的系统服务:

1. 基本用法

1     private void download() {
2 Request request = new Request(Uri.parse("http://files.cnblogs.com/wlrhnh/JeejenKnowledge-15793-release.apk"));
3 request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "4444.zip");
4 request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
5 long id = mDownloadMgr.enqueue(request);
6 Log.d("MMLL", "下载 id = " + id);
7 }

绿色代码指定文件下载路径,如果不指定,那么默认下载在“/data/data/com.android.providers.downloads/cache/***.apk”。代码中的id是个非常重要的属性,它表示DownloadManager给这次下载指定的ID,同时也是该文件在数据库中的column_id。默认行为,下载完成后Notification会自动消失;

红色代码表示下载完成后,Notification仍旧显示在下拉列表中,该API只能在API 11之后调用。

2. 获取下载文件的信息

API 11中新增了一个API,可以直接去到下载文件的Uri,如下:

1 Uri uri = mDownloadMgr.getUriForDownloadedFile(_id);
2 uri = file:///storage/emulated/0/Download/4444-4.zip //指定路径
3 uri = content://downloads/my_downloads/118 //默认路径

代码中红色log指的分别是指定路径和默认路径下得到的Uri,但是在API 低于11的系统中怎么使用呢?

DownloadManager提供了Query接口,代码如下:

 1     int _id = -1;
2 String local_filename = null;
3 String local_uri = null;
4 Query query = new Query();
5 Cursor cursor = mDownloadMgr.query(query);
6 if (cursor != null) {
7 cursor.moveToFirst();
8 _id = cursor.getInt(cursor.getColumnIndex("_id"));
9 local_filename = cursor.getString(cursor.getColumnIndex("local_filename"));
10 local_uri = cursor.getString(cursor.getColumnIndex("local_uri"));
11 }

上面代码中得到的Cursor的数量为1,且就是自己应用程序中调用DownloadManager下载的最新一次文件信息, 可以看到query既没有设置Uri,也没有指定_id,那怎么返回这唯一的一条信息呢?其实在生成query时有一些默认值,其中Uri如下:

1 /**
2 * The content:// URI to access downloads owned by the caller's UID.
3 */
4 public static final Uri CONTENT_URI = Uri.parse("content://downloads/my_downloads");

而且秘密就在注释中,查询时会更据caller的UID,所以才会返回自己下载的文件的信息;

cursor的全部Column如下:

 1 D/MMLL    (16614): column = _id
2 D/MMLL (16614): column = local_filename
3 D/MMLL (16614): column = mediaprovider_uri
4 D/MMLL (16614): column = destination
5 D/MMLL (16614): column = title
6 D/MMLL (16614): column = description
7 D/MMLL (16614): column = uri
8 D/MMLL (16614): column = status
9 D/MMLL (16614): column = hint
10 D/MMLL (16614): column = media_type
11 D/MMLL (16614): column = total_size
12 D/MMLL (16614): column = last_modified_timestamp
13 D/MMLL (16614): column = bytes_so_far
14 D/MMLL (16614): column = local_uri
15 D/MMLL (16614): column = reason
16 D/MMLL (16614): column = bypass_recommended_size_limit
17 D/MMLL (16614): column = allowed_network_types
18 D/MMLL (16614): column = entity

对应的值如下:

 1 D/MMLL    (22053): cursor.getString(0) = 107
2 D/MMLL (22053): cursor.getString(0) = /data/data/com.android.providers.downloads/cache/4_lauchmode.zip
3 D/MMLL (22053): cursor.getString(0) = null
4 D/MMLL (22053): cursor.getString(0) = 2
5 D/MMLL (22053): cursor.getString(0) = 4_lauchmode.zip
6 D/MMLL (22053): cursor.getString(0) =
7 D/MMLL (22053): cursor.getString(0) = http://files.cnblogs.com/wlrhnh/4_lauchmode.zip
8 D/MMLL (22053): cursor.getString(0) = 200
9 D/MMLL (22053): cursor.getString(0) = null
10 D/MMLL (22053): cursor.getString(0) = application/zip
11 D/MMLL (22053): cursor.getString(0) = 1315681
12 D/MMLL (22053): cursor.getString(0) = 1414137592255
13 D/MMLL (22053): cursor.getString(0) = 1315681
14 D/MMLL (22053): cursor.getString(0) = content://downloads/my_downloads/107
15 D/MMLL (22053): cursor.getString(0) = placeholder
16 D/MMLL (22053): cursor.getString(0) = 0
17 D/MMLL (22053): cursor.getString(0) = -1
18 D/MMLL (22053): cursor.getString(0) = null

或者

 1 D/MMLL    ( 8796): cursor.getString(0) = 113
2 D/MMLL ( 8796): cursor.getString(0) = /storage/emulated/0/Download/4444.zip
3 D/MMLL ( 8796): cursor.getString(0) = content://media/external/file/34731
4 D/MMLL ( 8796): cursor.getString(0) = 4
5 D/MMLL ( 8796): cursor.getString(0) = 4444.zip
6 D/MMLL ( 8796): cursor.getString(0) =
7 D/MMLL ( 8796): cursor.getString(0) = http://files.cnblogs.com/wlrhnh/4_lauchmode.zip
8 D/MMLL ( 8796): cursor.getString(0) = 200
9 D/MMLL ( 8796): cursor.getString(0) = file:///storage/emulated/0/Download/4444.zip
10 D/MMLL ( 8796): cursor.getString(0) = application/zip
11 D/MMLL ( 8796): cursor.getString(0) = 1315681
12 D/MMLL ( 8796): cursor.getString(0) = 1414149416875
13 D/MMLL ( 8796): cursor.getString(0) = 1315681
14 D/MMLL ( 8796): cursor.getString(0) = file:///storage/emulated/0/Download/4444.zip
15 D/MMLL ( 8796): cursor.getString(0) = placeholder
16 D/MMLL ( 8796): cursor.getString(0) = 0
17 D/MMLL ( 8796): cursor.getString(0) = -1
18 D/MMLL ( 8796): cursor.getString(0) = null

3. 监听下载状态的BroadCast,代码如下:

 1     private void regisiterBroadCast() {
2 IntentFilter intentFilter = new IntentFilter();
3 intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
4 intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
5 intentFilter.addAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
6
7 this.registerReceiver(new BroadcastReceiver() {
8 @Override
9 public void onReceive(Context context, Intent intent) {
10 if (intent != null) {
11 Log.d("MMLL", "intent.getAction = " + intent.getAction());
12 Bundle bundle = intent.getExtras();
13 if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
14 Log.d("MMLL", "ACTION_DOWNLOAD_COMPLETE");
15 } else if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(intent.getAction())) {
16 Log.d("MMLL", "ACTION_NOTIFICATION_CLICKED");
17 } else if (DownloadManager.ACTION_VIEW_DOWNLOADS.equals(intent.getAction())) {
18 Log.d("MMLL", "ACTION_VIEW_DOWNLOADS");
19 }
20 }
21 }
22 }, intentFilter);
23 }

除了下载完成后发送的广播能接受到之外,其他的两个广播暂时还收不到,待研究;

4. 如果下载的是APK,并且药调用Installer来安装,安装的代码如下:

1     private void installApk(Uri uri) {
2 Intent intent = new Intent(Intent.ACTION_VIEW);
3 intent.setDataAndType(uri, "application/vnd.android.package-archive");
4 startActivity(intent);
5 }

可见需要传入一个Uri,在前面的分析中,我们知道设置下载路径和默认下载路径返回的Uri是不一样的,

1 uri = file:///storage/emulated/0/Download/4444-4.zip //指定路径
2 uri = content://downloads/my_downloads/118 //默认路径

此时第一个uri传进去是可以正常安装的,但是第二个uri则不行,会提示“包解析失败”神马的,因此,如果下载的是APK,那么最好还是指定一下下载路径;

5. 那么在API 11之前如何获取Uri呢?

有两种方式:

1>. 前面提到的查询数据库,字段是local_uri

2>. 有一种比较复杂的方式,仅供参考:

 1     public Uri getDownloadFile() {
2 long downloadId = getDownloadId();
3 int status = queryDownloadStatus(downloadId);
4 if (DownloadManager.STATUS_SUCCESSFUL == status) {
5 if (Build.VERSION.SDK_INT >= 11) {
6 return mDownloadMgr.getUriForDownloadedFile(downloadId);
7 } else {
8 FileOutputStream outStream = null;
9 ParcelFileDescriptor.AutoCloseInputStream instream = null;
10 try {
11 ParcelFileDescriptor desc = mDownloadMgr.openDownloadedFile(downloadId);
12 instream = new ParcelFileDescriptor.AutoCloseInputStream(desc);
13
14 String fileName = Environment.getExternalStorageDirectory().getAbsolutePath().toString();
15 fileName += "/jeejen/" + Calendar.getInstance().getTimeInMillis() + "_" + downloadId + ".apk";
16 File file = new File(fileName);
17 if (!file.getParentFile().exists()) {
18 file.getParentFile().mkdirs();
19 }
20 file.createNewFile();
21 outStream = new FileOutputStream(file);
22 byte[] buffer = new byte[1024];
23 int read;
24
25 while ((read = instream.read(buffer)) != -1) {
26 outStream.write(buffer, 0, read);
27 }
28
29 return Uri.fromFile(file);
30 } catch (Exception e) {
31 e.printStackTrace();
32 return null;
33 } finally {
34 try {
35 if (outStream != null) {
36 outStream.close();
37 }
38 } catch (Exception e) {
39 }
40 try {
41 if (instream != null) {
42 instream.close();
43 }
44 } catch (Exception e) {
45 }
46 }
47 }
48 }
49 return null;
50 }

个人觉得这种方式比较复杂,但不失为一种思路。比较简单粗暴的方式是:

 1 private void copyToSD(String path) {
2 FileInputStream inputStream = null;
3 FileOutputStream outputStream = null;
4 try {
5 inputStream = new FileInputStream(path);
6 outputStream = new FileOutputStream("sdcard/jeejen/大卫.zip");
7 byte[] bb = new byte[1024];
8 int count = -1;
9 while ((count = inputStream.read(bb)) != -1) {
10 outputStream.write(bb, 0, count);
11 }
12 outputStream.flush();
13 } catch (FileNotFoundException e) {
14 e.printStackTrace();
15 } catch (IOException e) {
16 e.printStackTrace();
17 } finally {
18 if (inputStream != null) {
19 try {
20 inputStream.close();
21 } catch (IOException e) {
22 e.printStackTrace();
23 }
24 }
25 if (outputStream != null) {
26 try {
27 outputStream.close();
28 } catch (IOException e) {
29 e.printStackTrace();
30 }
31 }
32 }
33 }

把local_filename字段对应的值传进去即可;

6. 如何获取当前下载进度?

获取进度的基本原理是注册一个ContentObserver,因为伴随着下载,会往数据库中写入下载文件的大小和当前下载完成的大小。代码如下:

 1     private void getProgress(long id) {
2 long total_size = -1L;
3 long bytes_so_far = -1L;
4 Query query = new Query().setFilterById(id);
5 Cursor cur = mDownloadMgr.query(query);
6 if (cur != null && cur.moveToFirst()) {
7 do {
8 total_size = cur.getLong(cur.getColumnIndex("total_size"));
9 bytes_so_far = cur.getLong(cur.getColumnIndex("bytes_so_far"));
10 Log.d("MMLL", "bytes_so_far = " + bytes_so_far + ", total_size = " + total_size);
11 } while (cur.moveToNext());
12 }
13 }
14
15 private class DownloadChangeObserver extends ContentObserver {
16
17 public DownloadChangeObserver(Handler handler) {
18 super(handler);
19 }
20
21 @Override
22 public void onChange(boolean selfChange) {
23 super.onChange(selfChange);
24 getProgress(id);
25 }
26
27 /*@Override
28 public void onChange(boolean selfChange, Uri uri) {
29 super.onChange(selfChange, uri);
30 }*/
31
32 }

然后注册,如下:

1 getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, new DownloadChangeObserver(null));

OK,至此Over

DownloadManager补漏的更多相关文章

  1. [Android Pro] 判断Uri对应的ContentProvider所操作的数据库u存在,及DownloadManager的暂停,继续

    reference to : http://blog.csdn.net/u012858313/article/details/38821857 项目中遇到一个问题,就是用到DownloadManage ...

  2. app的自动更新(调用DownloadManager)

    具体思路为:调用接口与服务器版本对比,当服务器版本号大于本地的,调用DownloadManager进行下载,之前也试过很多方法,但是兼容性都不是很好,还有一点要注意的是,在这里我并没有设置固定的下载路 ...

  3. DownloadManager

    在androi中,volley适合小文件的获取和大并发,如果支持大文件的下载可以用Android原生的DownloadManager.DownloadManager默认支持多线程下载.断点续传等. 基 ...

  4. Android 使用 DownloadManager 管理系统下载任务的方法,android管理系统

    从Android 2.3(API level 9)开始Android用系统服务(Service)的方式提供了Download Manager来优化处理长时间的下载操作.Download Manager ...

  5. DownloadManager 的使用

    一.基本概念    1.DownloadManager是Android 2.3A (API level 9) 引入的,基于http协议,用于处理长时间下载. 2.DownloadManager对于断点 ...

  6. Android--调用系统的DownLoadManager去下载文件

    代码里面有详细的注释: /** * 该方法是调用了系统的下载管理器 */ public void downLoadApk(Context context,String url){ /** * 在这里返 ...

  7. 使用downloadmanager调用系统的下载

    /** * 文件名 UpdateDownload.java * 包含类名列表 com.issmobile.numlibrary.tool * 版本信息  版本号  * 创建日期 2014年7月14日  ...

  8. DownloadManager 下载管理类

    演示 简介 从Android 2.3开始新增了一个下载管理类,在SDK的文档中我们查找android.app.DownloadManager可以看到.下载管理类可以长期处理多个HTTP下载任务,客户端 ...

  9. 安卓开发之非常好用的AndroidOne框架DownloadManager

    AndroidOne框架是采用MVC模式,集成了Android主流开源技术及组件,是一款极速且简单高效开发框架,整个项目包含两个部分AndroidOne,oneCore AndroidOne为演示项目 ...

随机推荐

  1. zTree插件之多选下拉菜单代码

    zTree插件之多选下拉菜单代码 css和js <!--ztree树结构--> <link rel="stylesheet" type="text/cs ...

  2. 如何修改VPN连接的MTU,解决频繁断线和页面打不开的问题

    如何修改VPN连接的MTU,解决频繁断线和页面打不开的问题 MTU 介绍:MTU 即最大传输单元,它是指一种通信协议的某一层上面所能通过的最大数据包大小.为什么需要修改 MTU大多数设备原本支持通过 ...

  3. PHP 匹配一个汉字

    使用preg_match 必须使用u flag 这个修饰符添加的额外的功能,与Perl的PCRE不兼容. Pattern和字符串均为UTF-8编码. 从PHP 4.1.0 or greater on ...

  4. css3 calc()方法详解

    calc()对大家来说,或许很陌生,不太会相信calc()是css中的部分.因为看其外表像个函数,既然是函数为何又出现在CSS中呢?这一点也让我百思不得其解,今天有一同事告诉我,说CSS3中有一个属性 ...

  5. android setting 设置永不休眠

    默认情况下,Android系统在超过N分钟没操作,会自动关屏并进入休眠状态.  实际上,有些项目要求超时不休眠,如果只是针对单个应用程序,我们可以通过电源管理设置状态来实现, 而如果要设置所有应用的超 ...

  6. EasyUI datebox 只读和取值

    <input id="dd" type="text" class="easyui-datebox" required="re ...

  7. 【小白入门向】tarjan算法+codevs1332上白泽慧音 题解报告

    一.[前言]关于tarjan tarjan算法是由Robert Tarjan提出的求解有向图强连通分量的算法. 那么问题来了找蓝翔!(划掉)什么是强连通分量? 我们定义:如果两个顶点互相连通(即存在A ...

  8. 【Java】一个小程序,计算它包含的代码所需的耗时

    写一个小程序,用来计算它包含的代码所需的耗时.虽然简单,测试代码是否耗时还是有点用的,不用重新写嘛~ import java.util.Date; import java.util.concurren ...

  9. 【Nginx】配置Nginx的负载均衡

    参考的优秀文章 tomcat配置文件server.xml详解 AJP协议总结与分析 Using nginx as HTTP load balancer 在本机运行2个Tomcat 现需要运行两个Tom ...

  10. [poj3378] Crazy Thairs (DP + 树状数组维护 + 高精度)

    树状数组维护DP + 高精度 Description These days, Sempr is crazed on one problem named Crazy Thair. Given N (1 ...