EP28-DownloadManager分析(1)
DownloadManager分析(1)
Summary
DownloadManager
是Android系统封装好的一个功能,位于/android/app/目录下,实现了下载功能。文档是这么说的:
download manager是一个处理长时间http下载的系统服务。客户端可以发出请求,让URI下载到特定的文件中。download manager会在后台执行下载,处理HTTP交互,并且在网络变化之后导致连接失败/系统重启后能重新尝试下载。通过传递
DOWNLOAD_SERVICE
给getSystemService
来获得DownloadManager实例。通过这个API请求Download的App应该注册一个ACTION_NOTIFICATION_CLICKED
来处理用户在Notification或者UI中点击一个正在下载的进度的操作。
SystemService的启动
读完了Summary这段话有一个疑问,为什么通过getSystemService
才能获取实例。在Context的源码中发现,getSystemService
是在Context
中实现的抽象方法,具体是在framework的ContextImpl.java
中实现的,我们看到有一个专门盛放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里面,有一个函数在往MAP
里填东西:
private static void registerService(String serviceName, ServiceFetcher fetcher) { if (!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } //系统启动时往 SYSTEM_SERVICE_MAP.put(serviceName, fetcher); }
然后我们看到,同样是在这个类里面实现了所有系统Service的注册:
//通过static方法优先注册所有的service。 static { registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { return AccessibilityManager.getInstance(ctx); }});......
好了,上面我们看到了Service
被ServerFetcher
取出后添加进MAP
的动作;那么这些服务是谁初始化的?答案是SystemServer
。SystemServer
是Android的核心进程,由zygote
创建。所有服务都循环创建在SystemServer
上。
另外,ContextImpl跟Context是什么关系?我们在Application.java里面可以看到有ContextImpl的初始化,但是Context跟ContextImpl表面上并没有继承关系,虽然后者确实是前者的实现。
好了,我们得到一个结论,系统启动的时候,zygote帮忙启动了DownloadService这个SystemService,运行在SystemServer进程上。
从调用开始
回到最开始,我们最终开始下载,使用的是dowloadManager.enqueue(request);
这样的调用方式,enqueue
也就是把一个request加入队列,downloadmanager准备好了并且网络正常的时候会立刻开始下载。
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
准备的!唉,DownloadManager
看了半天,里面根本没有实现下载的操作,几乎全是「是否显示Notification」「下载进度查询」「下载成功监听」之类的管理性质的工作。
我查了资料里面说,在Android N之前的版本,这个DownloadProvider.insert()
执行之后,会直接以Context.startService的方式启动DownloadService
进行异步下载。先不说Android N之后的版本是怎么处理的,读到这里我脑中大概形成了这样一个模型:
-
DownloadManager
分发任务给DownloadProvider
-
DownloadProvider
调用DownloadService
-
DownloadService
真正执行下载操作
明天继续看。
References:
[1]http://www.cnblogs.com/adm1989/p/4631129.html
[2]https://segmentfault.com/q/1010000004457662
[3]http://www.jianshu.com/p/c9dc04af2f54#
更多相关文章
- Android视图加载流程(3)之ViewRootImpl的UI刷新机制
- android下载大图片避免OOM的解决方法
- Android(安卓)getSystemService()的API
- android系统屏幕亮度调节
- android窗口机制学习笔记
- Android(安卓)内存溢出(Out Of Memory)
- Android(安卓)P wakeup 亮屏流程
- 线程-进程间通信(操作系统、java、android)最全总结!
- 004. Android界面刷新没有调用OnMeasure