DownloadManager分析(1)
Summary
DownloadManager是Android系統(tǒng)封裝好的一個功能,位于/android/app/目錄下,實現(xiàn)了下載功能。文檔是這么說的:
download manager是一個處理長時間http下載的系統(tǒng)服務(wù)??蛻舳丝梢园l(fā)出請求,讓URI下載到特定的文件中。download manager會在后臺執(zhí)行下載,處理HTTP交互,并且在網(wǎng)絡(luò)變化之后導(dǎo)致連接失敗/系統(tǒng)重啟后能重新嘗試下載。通過傳遞
DOWNLOAD_SERVICE給getSystemService來獲得DownloadManager實例。通過這個API請求Download的App應(yīng)該注冊一個ACTION_NOTIFICATION_CLICKED來處理用戶在Notification或者UI中點擊一個正在下載的進度的操作。
SystemService的啟動
讀完了Summary這段話有一個疑問,為什么通過getSystemService才能獲取實例。在Context的源碼中發(fā)現(xiàn),getSystemService是在Context中實現(xiàn)的抽象方法,具體是在framework的ContextImpl.java中實現(xiàn)的,我們看到有一個專門盛放SystemService的SYSTEM_SERVICE_MAP:
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
看來是有人往這個SYSTEM_SERVICE_MAP里面加ServiceName了。在ContextImpl里面,有一個函數(shù)在往MAP里填東西:
private static void registerService(String serviceName, ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
//系統(tǒng)啟動時往
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}
然后我們看到,同樣是在這個類里面實現(xiàn)了所有系統(tǒng)Service的注冊:
//通過static方法優(yōu)先注冊所有的service。
static {
registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
public Object getService(ContextImpl ctx) {
return AccessibilityManager.getInstance(ctx);
}});
...
...
好了,上面我們看到了Service被ServerFetcher取出后添加進MAP的動作;那么這些服務(wù)是誰初始化的?答案是SystemServer。SystemServer是Android的核心進程,由zygote創(chuàng)建。所有服務(wù)都循環(huán)創(chuàng)建在SystemServer上。
另外,ContextImpl跟Context是什么關(guān)系?我們在Application.java里面可以看到有ContextImpl的初始化,但是Context跟ContextImpl表面上并沒有繼承關(guān)系,雖然后者確實是前者的實現(xiàn)。
好了,我們得到一個結(jié)論,系統(tǒng)啟動的時候,zygote幫忙啟動了DownloadService這個SystemService,運行在SystemServer進程上。
從調(diào)用開始
回到最開始,我們最終開始下載,使用的是dowloadManager.enqueue(request);這樣的調(diào)用方式,enqueue也就是把一個request加入隊列,downloadmanager準(zhǔn)備好了并且網(wǎng)絡(luò)正常的時候會立刻開始下載。
public long enqueue(Request request) {
//把request添加進ContentValues(類似hashmap)里
ContentValues values = request.toContentValues(mPackageName);
Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
long id = Long.parseLong(downloadUri.getLastPathSegment());
return id;
}
這里厲害了,toContentValues方法的說明是:
ContentValues to be passed to DownloadProvider.insert()
也就是說這個request實際上是給DownloadProvider準(zhǔn)備的!唉,DownloadManager看了半天,里面根本沒有實現(xiàn)下載的操作,幾乎全是「是否顯示Notification」「下載進度查詢」「下載成功監(jiān)聽」之類的管理性質(zhì)的工作。
我查了資料里面說,在Android N之前的版本,這個DownloadProvider.insert()執(zhí)行之后,會直接以Context.startService的方式啟動DownloadService進行異步下載。先不說Android N之后的版本是怎么處理的,讀到這里我腦中大概形成了這樣一個模型:
-
DownloadManager分發(fā)任務(wù)給DownloadProvider -
DownloadProvider調(diào)用DownloadService -
DownloadService真正執(zhí)行下載操作
明天繼續(xù)看。
References:
[1]http://www.cnblogs.com/adm1989/p/4631129.html
[2]https://segmentfault.com/q/1010000004457662
[3]http://www.itdecent.cn/p/c9dc04af2f54#