本文主要結合源碼介紹android系統下載下傳管理downloadmanager的強大功能及使用。
關于下載下傳管理的廢話
一、downloadmanager簡單介紹
downloadmanager主要提供了下面幾個接口:
public long enqueue(request request)執行下載下傳,傳回downloadid,downloadid可用于後面查詢下載下傳資訊。若網絡不滿足條件、sdcard挂載中、超過最大并發數等異常會等待下載下傳,正常則直接下載下傳。
public int remove(long… ids)删除下載下傳,若下載下傳中取消下載下傳。會同時删除下載下傳檔案和記錄。
public cursor query(query query)查詢下載下傳資訊。
public static long getrecommendedmaxbytesovermobile(context context通過移動網絡下載下傳的最大位元組數
public string getmimetypefordownloadedfile(long id)得到下載下傳的mimetype,如何設定後面會進行介紹
其它:通過檢視代碼我們可以發現還有個cursortranslator私有靜态内部類。這個類主要對query做了一層代理。将downloadprovider和downloadmanager之間做個映射。将downloadprovider中的十幾種狀态對應到了downloadmanager中的五種狀态,downloadprovider中的失敗、暫停原因轉換為了downloadmanager的原因。
二、下載下傳管理示例
下面具體介紹利用downloadmanager進行下載下傳。
1、androidmanifest中添權重限
java
1
2
<uses-permission android:name="android.permission.internet" />
<uses-permission android:name="android.permission.write_external_storage" />
網絡通路權限是必須的,下載下傳位址為sdcard的話需要添加sdcard寫權限。
2、調用downloadmanager.request開始下載下傳
3
4
5
6
7
8
9
10
11
downloadmanager downloadmanager = (downloadmanager)getsystemservice(download_service);
string apkurl = "http://img.meilishuo.net/css/images/androidshare/meilishuo_3.6.1_10006.apk";
downloadmanager.request request = new downloadmanager.request(uri.parse(apkurl));
request.setdestinationinexternalpublicdir("trinea", "meilishuo.apk");
// request.settitle("meilishuo");
// request.setdescription("meilishuo desc");
// request.setnotificationvisibility(downloadmanager.request.visibility_visible_notify_completed);
// request.setallowednetworktypes(downloadmanager.request.network_wifi);
// request.setnotificationvisibility(downloadmanager.request.visibility_hidden);
// request.setmimetype("application/cn.trinea.download.file");
long downloadid = downloadmanager.enqueue(request);
上面調用downloadmanager的enqueue接口進行下載下傳,傳回唯一的downloadid。
downloadmanager.request除了構造函數的uri必須外,其他設定都為可選設定。下面逐個介紹下:
request.setdestinationinexternalpublicdir(“trinea”, “meilishuo.apk”);表示設定下載下傳位址為sd卡的trinea檔案夾,檔案名為meilishuo.apk。
setdestinationinexternalpublicdir源碼
從源碼中我們可以看出下載下傳完整目錄為environment.getexternalstoragepublicdirectory(dirtype)。不過file是通過file.mkdir()建立的,這樣如果上級目錄不存在就會建立檔案夾異常。是以下載下傳前我們最好自己調用file的mkdirs方法遞歸建立子目錄,如下:
file folder = new file(foldername);
return (folder.exists() && folder.isdirectory()) ? true : folder.mkdirs();
否則,會報異常
java.lang.illegalstateexception: unable to create directory: /storage/sdcard0/trinea/aa
at android.app.downloadmanager$request.setdestinationinexternalpublicdir(downloadmanager.java)
其他設定下載下傳路徑接口為setdestinationuri,setdestinationinexternalfilesdir,setdestinationtosystemcache。其中setdestinationtosystemcache僅限系統app使用。
request.allowscanningbymediascanner();表示允許mediascanner掃描到這個檔案,預設不允許。
request.settitle(“meilishuo”);設定下載下傳中通知欄提示的标題
request.setdescription(“meilishuo desc”);設定下載下傳中通知欄提示的介紹
request.setnotificationvisibility(downloadmanager.request.visibility_visible_notify_completed);
表示下載下傳進行中和下載下傳完成的通知欄是否顯示。預設隻顯示下載下傳中通知。visibility_visible_notify_completed表示下載下傳完成後顯示通知欄提示。visibility_hidden表示不顯示任何通知欄提示,這個需要在androidmainfest中添權重限android.permission.download_without_notification.
request.setallowednetworktypes(downloadmanager.request.network_wifi);
表示下載下傳允許的網絡類型,預設在任何網絡下都允許下載下傳。有network_mobile、network_wifi、network_bluetooth三種及其組合可供選擇。如果隻允許wifi下載下傳,而目前網絡為3g,則下載下傳會等待。
request.setallowedoverroaming(boolean allow)移動網絡情況下是否允許漫遊。
request.setmimetype(“application/cn.trinea.download.file”);
設定下載下傳檔案的minetype。因為下載下傳管理ui中點選某個已下載下傳完成檔案及下載下傳完成點選通知欄提示都會根據mimetype去打開檔案,是以我們可以利用這個屬性。比如上面設定了mimetype為application/cn.trinea.download.file,我們可以同時設定某個activity的intent-filter為application/cn.trinea.download.file,用于響應點選的打開檔案。
<intent-filter>
<action android:name="android.intent.action.view" />
<category android:name="android.intent.category.default" />
<data android:mimetype="application/cn.trinea.download.file" />
</intent-filter>
request.addrequestheader(string header, string value)
添加請求下載下傳的網絡連結的http頭,比如user-agent,gzip壓縮等
3 下載下傳進度狀态監聽及查詢
下載下傳進度狀态監聽代碼
其中我們會監聽uri.parse(“content://downloads/my_downloads”)。然後查詢下載下傳狀态和進度,發送handler進行更新,handler中處理就是設定進度條和狀态等。
下載下傳進度狀态查詢代碼
從上面代碼可以看出我們主要調用downloadmanager.query()進行查詢。downloadmanager.query為下載下傳管理對外開放的資訊查詢類,主要包括以下接口:
setfilterbyid(long… ids)根據下載下傳id進行過濾
setfilterbystatus(int flags)根據下載下傳狀态進行過濾
setonlyincludevisibleindownloadsui(boolean value)根據是否在download ui中可見進行過濾。
orderby(string column, int direction)根據列進行排序,不過目前僅支援downloadmanager.column_last_modified_timestamp和downloadmanager.column_total_size_bytes排序。
4 下載下傳成功監聽
下載下傳完成後,下載下傳管理會發出downloadmanager.action_download_complete這個廣播,并傳遞downloadid作為參數。通過接受廣播我們可以打開對下載下傳完成的内容進行操作。代碼如下:
下載下傳成功監聽
5、響應通知欄點選
(1) 響應下載下傳中通知欄點選
點選下載下傳中通知欄提示,系統會對下載下傳的應用單獨發送action為downloadmanager.action_notification_clicked廣播。intent.getdata為content://downloads/all_downloads/29669,最後一位為downloadid。
如果同時下載下傳多個應用,intent會包含downloadmanager.extra_notification_click_download_ids這個key,表示下載下傳的的downloadid數組。這裡設計到下載下傳管理通知欄的顯示機制,會在下一篇具體介紹。
(2) 響應下載下傳完成通知欄點選
下載下傳完後會調用下面代碼進行處理,從中我們可以發現系統會調用view action根據mimetype去查詢。是以可以利用我們在介紹的downloadmanager.request的setmimetype函數。
opendownload源碼
如果界面上過多元素需要更新,且網速較快不斷的執行onchange會對頁面性能有一定影響。推薦scheduledexecutorservice定期查詢,如下:
public static scheduledexecutorservice scheduledexecutorservice = executors.newscheduledthreadpool(3);
runnable command = new runnable() {
@override
public void run() {
updateview();
}
};
scheduledexecutorservice.scheduleatfixedrate(command, 0, 3, timeunit.seconds);
表示3秒定時重新整理