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地址爲: