从Android 2.3(API level 9)开始Android用系统服务(Service)的方式提供了Download Manager来优化处理长时间的下载操作。Download Manager处理HTTP
连接并监控连接中的状态变化以及系统重启来确保每一个下载任务顺利完成。
在大多数涉及到下载的情况中使用Download Manager都是不错的选择,特别是当用户切换不同的应用以后下载需要在后台继续进行,以及对下载完成的处理相当重要的时候
相对比传统下载方式,Download Manager具有以下优点:
- 采用service对下载处理做了很好的封装,同时封装了大部分异常处理,程序可专注于逻辑处理
- 对于断点续传功能有很好的支持
例子:
下载文件,在这里返回的reference变量是系统为当前的下载请求分配的一个唯一的ID,我们可以通过这个ID重新获得这个下载任务,进行一些自己想要进行的操作或者查询
下载的状态以及取消下载等等。
我们可以通过addRequestHeader方法为DownloadManager.Request对象request添加HTTP头,也可以通过setMimeType方法重写从服务器返回的mime type。
我们还可以指定在什么连接状态下执行下载操作。setAllowedNetworkTypes方法可以用来限定在WiFi还是手机网络下进行下载,setAllowedOverRoaming方法
可以用来阻止手机在漫游状态下下载。
private void DownloadFile() { String serviceString = Context.DOWNLOAD_SERVICE; DownloadManager downloadManager; downloadManager = (DownloadManager)getSystemService(serviceString); //创建下载请求 Uri uri = Uri.parse("http://developer.android.com/shareables/icon_templates-v4.0.zip"); DownloadManager.Request request = new Request(uri);
//设置允许使用的网络类型,这里是移动网络和wifi都可以
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE|DownloadManager.Request.NETWORK_WIFI);
//将下载请求放入队列 long reference = downloadManager.enqueue(request); myDownloadReference = reference; Log.d(TAG, "Download Reference: " + reference); }
注册一个广播接受者来接收ACTION_DOWNLOAD_COMPLETE广播对下载完成的处理,
这个广播会包含一个EXTRA_DOWNLOAD_ID信息在intent中包含了已经完成的这个下载的ID,
query方法返回一个包含了下载任务细节的Cursor。
query方法传递一个DownloadManager.Query对象作为参数,通过DownloadManager.Query对象的setFilterById方法可以筛选我们希望查询的下
载任务的ID。也可以使用setFilterByStatus方法筛选我们希望查询的某一种状态的下载任务,传递的参数是DownloadManager.STATUS_*常量,可以指定
正在进行、暂停、失败、完成四种状态。
Download Manager包含了一系列COLUMN_*静态String常量,可以用来查询Cursor中的结果列索引。我们可以查询到下载任务的各种细节,包括状态,
文件大小,已经下载的字节数,标题,描述,URI,本地文件名和URI,媒体类型以及Media Provider download URI。
final DownloadManager downloadManager = (DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE); /** * Listing 6-4: Monitoring downloads for completion */ IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { long reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); if (myDownloadReference == reference) { Query myDownloadQuery = new Query(); myDownloadQuery.setFilterById(reference); Cursor myDownload = downloadManager.query(myDownloadQuery); if (myDownload.moveToFirst()) { int fileNameIdx = myDownload.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); int fileUriIdx = myDownload.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI); String fileName = myDownload.getString(fileNameIdx); String fileUri = myDownload.getString(fileUriIdx); // TODO Do something with the file. Log.d(TAG, fileName + " : " + fileUri); } myDownload.close(); } } }; registerReceiver(receiver, filter);
注册一个BroadcastReceiver来监控处理ACTION_NOTIFICATION_CLICKED action:
private void notificationClick() { IntentFilter filter = new IntentFilter(DownloadManager.ACTION_NOTIFICATION_CLICKED); BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String extraID = DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS; long[] references = intent.getLongArrayExtra(extraID); for (long reference : references) if (reference == myDownloadReference) { // Do something with downloading file. } } }; registerReceiver(receiver, filter); } private void listing607() { /**
默认情况下,所有通过Download Manager下载的文件都保存在一个共享下载缓存中,使用系统生成的文件名每一个Request对象都可以制定一个下载
保存的地址,通常情况下,所有的下载文件都应该保存在外部存储中,所以我们需要在应用清单文件中加上WRITE_EXTERNAL_STORAGE权限,
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
否则,会报错!
AndroidManifest.xml文件内容如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.paad.internet" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".MyActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Download Manager Notifications样式定制
默认情况下,通知栏中会显示被Download Manager管理的每一个download每一个Notification会显示当前的下载进度和文件的名字,可以更改其样式,一些常用的接口如下所示,可基于自身的应用要求进行调整
禁止发出通知,既后台下载
request.setShowRunningNotification(false);
不显示下载界面
request.setVisibleInDownloadsUi(false);
设置下载后文件存放的位置
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, “Bugdroid.png”)
附上书上的一个Sample: download manage