DownloadManager是android提供的一个系统服务,用于处理长期运行的HTTP下载。客户端可以将一个URI代表的一个网络资源文件下载到指定的目录。DownloadManager将会在后台执行下载任务,处理所有的HTTP交互,在下载失败或系统重启后继续下载任务。
DownloadManager的使用非常简单,当客户端需要发起一个下载任务时,需要创建一个DownloadManager.Request对象,并进行必要的设置:
String downloadUrl = "http://192.168.1.33/20131227_141739.mp4";
Uri downloadUri = Uri.parse(downloadUrl);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);
// 仅WiFi下允许下载
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
// 漫游时不下载,防止产生漫游费用
request.setAllowedOverRoaming(false);
// 下载文件描述
request.setDescription("Downloading 20131227_141739.mp4");
// 下载存储路径
// 文件将存放在外部存储的确实download文件内,如果无此文件夹,创建之,如果有,下面将返回false。
// 不同的手机不同Android版本的SD卡的挂载点可能会不一样,因此通过系统方式获取。
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdir();
request.setDestinationInExternalPublicDir("/download/", "20131227_142027.mp4");
// 下载文件类型
String extension = MimeTypeMap.getFileExtensionFromUrl(downloadUrl);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
request.setMimeType(mimeType);
// 设置UI是否可见
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
// 下载标题
request.setTitle("20131227_141739.mp4");
request.setVisibleInDownloadsUi(false);
创建完成request后,需要将该request提交给DownloadManager,
mDownloadId = mDownloadManager.enqueue(request);
返回的下载ID可以用来查询下载任务的执行状态,成功或失败。客户端需要创建一个DownloadManager.Query对象进行查询:
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(mDownloadId);
Cursor cursor = mDownloadManager.query(query);
if (cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch (status) {
case DownloadManager.STATUS_FAILED:
text = "download failed";
break;
case DownloadManager.STATUS_PAUSED:
text = "download paused";
break;
case DownloadManager.STATUS_PENDING:
text = "download pending";
break;
case DownloadManager.STATUS_RUNNING:
text = "download running";
break;
case DownloadManager.STATUS_SUCCESSFUL:
text = "download successful";
break;
default:
break;
}
}
cursor.close();
Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
要删除某一个下载任务,可以调用DownloadManager的remove方法:
mDownloadManager.remove(mDownloadId);
可以使用DownloadManager.ACTION_VIEW_DOWNLOADS来启动一个activity来查看所有下载任务:
startActivity(new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS));
如果客户端要监听任务的下载状态,或用户点击通知栏的点击事件,则需要注册一个receiver,来监听DownloadManager.ACTION_DOWNLOAD_COMPLETE和DownloadManager.ACTION_NOTIFICATION_CLICKED两个广播:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
Toast.makeText(MainActivity.this, id + " Finished", Toast.LENGTH_SHORT).show();
} else if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
long[] ids = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
Toast.makeText(MainActivity.this, StringUtils.join(ids, ',') + " clicked", Toast.LENGTH_SHORT).show();
}
}
};
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
registerReceiver(mReceiver, intentFilter);
至此,基本的下载任务就完成了。
完整代码如下:
package com.example.downloadmanager;
import org.apache.commons.lang3.StringUtils;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.MimeTypeMap;
import android.widget.Toast;
public class MainActivity extends Activity {
private long mDownloadId = 0;
private DownloadManager mDownloadManager = null;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
Toast.makeText(MainActivity.this, id + " Finished", Toast.LENGTH_SHORT).show();
} else if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
long[] ids = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
Toast.makeText(MainActivity.this, StringUtils.join(ids, ',') + " clicked", Toast.LENGTH_SHORT).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
findViewById(R.id.btn_start_download).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String downloadUrl = "http://192.168.1.33/20131227_141739.mp4";
Uri downloadUri = Uri.parse(downloadUrl);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);
// 仅WiFi下允许下载
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
// 漫游时不下载,防止产生漫游费用
request.setAllowedOverRoaming(false);
// 下载文件描述
request.setDescription("Downloading 20131227_141739.mp4");
// 下载存储路径
// 文件将存放在外部存储的确实download文件内,如果无此文件夹,创建之,如果有,下面将返回false。
// 不同的手机不同Android版本的SD卡的挂载点可能会不一样,因此通过系统方式获取。
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdir();
request.setDestinationInExternalPublicDir("/download/", "20131227_142027.mp4");
// 下载文件类型
String extension = MimeTypeMap.getFileExtensionFromUrl(downloadUrl);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
request.setMimeType(mimeType);
// 设置UI是否可见
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
// 下载标题
request.setTitle("20131227_141739.mp4");
request.setVisibleInDownloadsUi(false);
mDownloadId = mDownloadManager.enqueue(request);
}
});
findViewById(R.id.btn_query_status).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String text = "";
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(mDownloadId);
Cursor cursor = mDownloadManager.query(query);
if (cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch (status) {
case DownloadManager.STATUS_FAILED:
text = "download failed";
break;
case DownloadManager.STATUS_PAUSED:
text = "download paused";
break;
case DownloadManager.STATUS_PENDING:
text = "download pending";
break;
case DownloadManager.STATUS_RUNNING:
text = "download running";
break;
case DownloadManager.STATUS_SUCCESSFUL:
text = "download successful";
break;
default:
break;
}
}
cursor.close();
Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
}
});
findViewById(R.id.btn_view_log).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.this.startActivity(new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS));
}
});
findViewById(R.id.btn_stop_download).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mDownloadManager.remove(mDownloadId);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
registerReceiver(mReceiver, intentFilter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
}
需要说明的是,DownloadManager提供的下载功能非常简单,可能无法满足实际的需求,比如没有断点续传功能,没有暂停和继续。幸运的是已经有开源的库帮我们实现了这些功能,DownloadProvider就是其中一个,其github地址为: