Android 使用 DownloadManager 管理系統下載任務的方法

weixin_34321977發表於2017-05-06

在紅黑聯盟上看到的。這幾天一直考慮做一個Notification 的帶下載功能的自己定義通知。但沒搞出來。無意中在論壇看到這個。先Mark,明天試試。

從Android 2.3(API level 9)開始Android用系統服務(Service)的方式提供了Download Manager來優化處理長時間的下載操作。

Download Manager處理HTTP連線並監控連線中的狀態變化以及系統重新啟動來確保每個下載任務順利完畢。

在大多數涉及到下載的情況中使用Download Manager都是不錯的選擇,特別是當使用者切換不同的應用以後下載須要在後臺繼續進行,以及當下載任務順利完畢非常重要的情況(DownloadManager對於斷點續傳功能支援非常好)。

要想使用Download Manager。使用getSystemService方法請求系統的DOWNLOAD_SERVICE服務,程式碼片段例如以下:

String serviceString =Context.DOWNLOAD_SERVICE; 
DownloadManager downloadManager; 
downloadManager = (DownloadManager)getSystemService(serviceString);


下載檔案

要請求一個下載操作。須要建立一個DownloadManager.Request物件,將要請求下載的檔案的Uri傳遞給DownloadManager的enqueue方法,程式碼片段例如以下所看到的:

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 = newRequest(uri); 
long reference =downloadManager.enqueue(request);


在這裡返回的reference變數是系統為當前的下載請求分配的一個唯一的ID。我們能夠通過這個ID又一次獲得這個下載任務,進行一些自己想要進行的操作或者查詢下載的狀態以及取消下載等等。

我們能夠通過addRequestHeader方法為DownloadManager.Request物件request加入HTTP頭,也能夠通過setMimeType方法重寫從server返回的mimetype。

我們還能夠指定在什麼連線狀態下執行下載操作。setAllowedNetworkTypes方法能夠用來限定在WiFi還是手機網路下進行下載。setAllowedOverRoaming方法能夠用來阻止手機在漫遊狀態下下載。

以下的程式碼片段用於指定一個較大的檔案僅僅能在WiFi下進行下載:

request.setAllowedNetworkTypes(Request.NETWORK_WIFI);

Android API level 11 介紹了getRecommendedMaxBytesOverMobile類方法(靜態方法)。返回一個當前手機網路連線下的最大建議位元組數,能夠來推斷下載是否應該限定在WiFi條件下。呼叫enqueue方法之後,僅僅要資料連線可用而且Download Manager可用。下載就會開始。要在下載完畢的時候獲得一個系統通知(notification),註冊一個廣播接受者來接收ACTION_DOWNLOAD_COMPLETE廣播。這個廣播會包括一個EXTRA_DOWNLOAD_ID資訊在intent中包括了已經完畢的這個下載的ID,程式碼片段例如以下所看到的:

IntentFilter filter = newIntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); 
      
BroadcastReceiver receiver = newBroadcastReceiver() { 
 @Override
 public void onReceive(Context context, Intent intent) { 
   long reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1); 
   if (myDownloadReference == reference) { 
       
   } 
 } 
}; 
registerReceiver(receiver, filter);

使用Download Manager的openDownloadedFile方法能夠開啟一個已經下載完畢的檔案。返回一個ParcelFileDescriptor物件。我們能夠通過Download Manager來查詢下載檔案的儲存地址。假設在下載時制定了路徑和檔名稱,我們也能夠直接操作檔案。

我們能夠為ACTION_NOTIFICATION_CLICKED action註冊一個廣播接受者,當使用者從通知欄點選了一個下載專案或者從Downloads app點選可一個下載的專案的時候,系統就會發出一個點選下載項的廣播。
程式碼片段例如以下:

IntentFilter filter = newIntentFilter(DownloadManager.ACTION_NOTIFICATION_CLICKED); 
  
BroadcastReceiver receiver = newBroadcastReceiver() { 
 @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);

定製Download Manager Notifications的樣式

預設情況下,通知欄中會顯示被Download Manager管理的每個download每個Notification會顯示當前的下載進度和檔案的名字

通過Download Manager能夠為每個download request定製Notification的樣式。包含全然隱藏Notification。以下的程式碼片段顯示了通過setTitle和setDescription方法來定製顯示在檔案下載Notification中顯示的文字。

request.setTitle(“Earthquakes”); 
request.setDescription(“EarthquakeXML”);

setNotificationVisibility方法能夠用來控制什麼時候顯示Notification,甚至是隱藏該request的Notification。有下面幾個引數:

Request.VISIBILITY_VISIBLE:在下載進行的過程中。通知欄中會一直顯示該下載的Notification,當下載完畢時,該Notification會被移除。這是預設的引數值。

Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED:在下載過程中通知欄會一直顯示該下載的Notification。在下載完畢後該Notification會繼續顯示。直到使用者點選該Notification或者消除該Notification。

Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION:僅僅有在下載完畢後該Notification才會被顯示。

Request.VISIBILITY_HIDDEN:不顯示該下載請求的Notification。假設要使用這個引數,須要在應用的清單檔案里加上DOWNLOAD_WITHOUT_NOTIFICATION許可權。

指定下載儲存地址

預設情況下,全部通過Download Manager下載的檔案都儲存在一個共享下載快取中,使用系統生成的檔名稱每個Request物件都能夠制定一個下載

儲存的地址,通常情況下。全部的下載檔案都應該儲存在外部儲存中,所以我們須要在應用清單檔案里加上WRITE_EXTERNAL_STORAGE許可權:

<uses-permissionandroid:name=”android.permission.write_external_storage”>

以下的程式碼片段是在外部儲存中指定一個隨意的儲存位置的方法:

request.setDestinationUri(Uri.fromFile(f));

f是一個File物件。

假設下載的這個檔案是你的應用所專用的。你可能會希望把這個檔案放在你的應用在外部儲存中的一個專有目錄中。注意這個目錄不提供訪問控制。所以其它的應用也能夠訪問這個目錄。在這樣的情況下,假設你的應用解除安裝了。那麼在這個目錄也會被刪除。

以下的程式碼片段是指定儲存檔案的路徑是應用在外部儲存中的專用目錄的方法:

request.setDestinationInExternalFilesDir(this, 
 Environment.DIRECTORY_DOWNLOADS, “Bugdroid.png”);

假設下載的檔案希望被其它的應用共享。特別是那些你下載下來希望被Media Scanner掃描到的檔案(比方音樂檔案),那麼你能夠指定你的下載路徑在外部儲存的公共目錄之下,以下的程式碼片段是將檔案存放到外部儲存中的公共音樂目錄的方法:

request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC, 
 "Android_Rock.mp3");

在預設的情況下。通過Download Manager下載的檔案是不能被Media Scanner掃描到的,進而這些下載的檔案(音樂、視訊等)就不會在Gallery和

Music Player這種應用中看到。

為了讓下載的音樂檔案能夠被其它應用掃描到,我們須要呼叫Request物件的allowScaningByMediaScanner方法。

假設我們希望下載的檔案能夠被系統的Downloads應用掃描到並管理,我們須要呼叫Request物件的setVisibleInDownloadsUi方法,傳遞引數true。

取消和刪除下載

Download Manager的remove方法能夠用來取消一個準備進行的下載,中止一個正在進行的下載,或者刪除一個已經完畢的下載。

remove方法接受若干個download 的ID作為引數,你能夠設定一個或者幾個你想要取消的下載的ID,例如以下程式碼段所看到的:

downloadManager.remove(REFERENCE_1,REFERENCE_2, REFERENCE_3);

該方法返回成功取消的下載的個數,假設一個下載被取消了,全部相關聯的檔案,部分下載的檔案和全然下載的檔案都會被刪除。

查詢Download Manager

你能夠通過查詢Download Manager來獲得下載任務的狀態。進度,以及各種細節,通過query方法返回一個包括了下載任務細節的Cursor。query方法傳遞一個DownloadManager.Query物件作為引數。通過DownloadManager.Query物件的setFilterById方法能夠篩選我們希望查詢的下載任務的ID。也能夠使用setFilterByStatus方法篩選我們希望查詢的某一種狀態的下載任務,傳遞的引數是DownloadManager.STATUS_*常量。能夠指定

正在進行、暫停、失敗、完畢四種狀態。

Download Manager包括了一系列COLUMN_*靜態String常量。能夠用來查詢Cursor中的結果列索引。我們能夠查詢到下載任務的各種細節,包括狀態。檔案大小。已經下載的位元組數。標題,描寫敘述,URI。本地檔名稱和URI,媒體型別以及Media Provider download URI。

以下的程式碼段是通過註冊監聽下載完畢事件的廣播接受者來查詢下載完畢檔案的本地檔名稱和URI的實現方法:


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(); 
  
 } 
}

對於暫停和失敗的下載,我們能夠通過查詢COLUMN_REASON列查詢出原因的整數碼。

對於STATUS_PAUSED狀態的下載,能夠通過DownloadManager.PAUSED_*靜態常量來翻譯出原因的整數碼,進而推斷出下載是因為等待網路連線

還是等待WiFi連線還是準備又一次下載三種原因而暫停。

對於STATUS_FAILED狀態的下載。我們能夠通過DownloadManager.ERROR_*來推斷失敗的原因。可能是錯誤碼(失敗原因)包含沒有儲存裝置。

儲存空間不足,反覆的檔名稱,或者HTTP errors。

以下的程式碼是怎樣查詢出當前全部的暫停的下載任務。提取出暫停的原因以及檔名。下載標題以及當前進度的實現方法:

// Obtain the Download ManagerService. 
String serviceString =Context.DOWNLOAD_SERVICE; 
DownloadManager downloadManager; 
downloadManager =(DownloadManager)getSystemService(serviceString); 
  
// Create a query for pauseddownloads. 
Query pausedDownloadQuery = newQuery(); 
pausedDownloadQuery.setFilterByStatus(DownloadManager.STATUS_PAUSED); 
  
// Query the Download Manager for pauseddownloads. 
Cursor pausedDownloads =downloadManager.query(pausedDownloadQuery); 
  
// Find the column indexes for the data werequire. 
int reasonIdx =pausedDownloads.getColumnIndex(DownloadManager.COLUMN_REASON); 
int titleIdx =pausedDownloads.getColumnIndex(DownloadManager.COLUMN_TITLE); 
int fileSizeIdx =  
 pausedDownloads.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);     
int bytesDLIdx =  
 pausedDownloads.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); 
  
// Iterate over the result Cursor. 
while (pausedDownloads.moveToNext()) { 
  //Extract the data we require from the Cursor. 
 String title = pausedDownloads.getString(titleIdx); 
  intfileSize = pausedDownloads.getInt(fileSizeIdx); 
  intbytesDL = pausedDownloads.getInt(bytesDLIdx); 
  
  //Translate the pause reason to friendly text. 
  intreason = pausedDownloads.getInt(reasonIdx); 
 String reasonString = "Unknown"; 
 switch (reason) { 
   case DownloadManager.PAUSED_QUEUED_FOR_WIFI :  
     reasonString = "Waiting for WiFi"; break; 
   case DownloadManager.PAUSED_WAITING_FOR_NETWORK :  
     reasonString = "Waiting for connectivity"; break; 
   case DownloadManager.PAUSED_WAITING_TO_RETRY : 
     reasonString = "Waiting to retry"; break; 
   default : break; 
 } 
  
  //Construct a status summary 
 StringBuilder sb = new StringBuilder(); 
 sb.append(title).append("\n"); 
 sb.append(reasonString).append("\n"); 
 sb.append("Downloaded ").append(bytesDL).append(" /" ).append(fileSize); 
  
  //Display the status  
 Log.d("DOWNLOAD", sb.toString()); 
} 
  
// Close the result Cursor. 
pausedDownloads.close();  


相關文章