EP28-DownloadManager分析(1)

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_SERVICEgetSystemService來獲得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);
                }});
...
...

好了,上面我們看到了ServiceServerFetcher取出后添加進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#

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容