Android Download机制详解(一)DocumentUI部分
来源:互联网 发布:图片滚动播放软件 编辑:程序博客网 时间:2024/06/02 15:17
在Android中Google为我们集成了一套十分便利的Download机制,用来下载网络上的资源文件。以此省去了我们编写和维护大量与Download相关的代码。
组成
Android中Download由三个部分组成:
1.DocumentsUI -----> /frameworks/base/packages/DocumentsUI/
2.DownloadManager ---->/frameworks/base/core/java/android/app/
3.DownloadProvider ---->/packages/providers/DownloadProvider/
下图中用MVC的分层将这三部分做了划分:
其中DocumentsUI作为视图层(V)负责展示Download信息
DownloadManager和DownloadProvder的一部分作为控制层(C)负责下载的逻辑控制
DownloadProvder的另一部分则作为数据层(M)负责数据的存储
总流程
Download的整个流程在上图中已经表示的很明显了,这里不做过对赘述,详细讲解将放在后面。
值得注意的是DownloadManager看似是主宰整个下载过程的角色,但事实并非如此正真的幕后“黑手”是DownloadProvider。
详细分析
DocumentUI--数据显示篇
DocumentsUI是一个可见程序,但即便如此Launcher上也没有直接打开的DocumentsUI的入口。它的入口一般有两个:
- Launcher上的“下载”app
- 被其他app唤起如(短信点击添加附件后唤起的app就是DocumentsUI)
这里我们只分析1这种情况,情况2的话感兴趣的同学可以自己学习一下。
“下载”这个app的代码被包含在了DownloadProvider中,具体位置如下:
上图中的ui文件夹就是包含“下载”app的所有代码.
根据AndroidManifest文件判断,点击“下载”app首先启动的activity是:
/packages/providers/DownloadProvider/ui/src/com/android/providers/downloads/ui/DownloadList.java
我们来看一下这个文件的内容:
17package com.android.providers.downloads.ui;1819import android.app.Activity;20import android.content.Intent;21import android.os.Bundle;22import android.provider.DocumentsContract;2324import com.android.providers.downloads.Constants;2526public class DownloadList extends Activity {27 @Override28 public void onCreate(Bundle icicle) {29 super.onCreate(icicle);3031 // Trampoline over to new management UI32 final Intent intent = new Intent(DocumentsContract.ACTION_MANAGE_ROOT);33 intent.setData(DocumentsContract.buildRootUri(34 Constants.STORAGE_AUTHORITY, Constants.STORAGE_ROOT_ID));35 startActivity(intent);36 finish();37 }38}
看到这里大家应该知道了,其实这个“下载”app只是一个传送门,传送门的另一边是Action包含“DocumentsContract.ACTION_MANAGE_ROOT”的Activity,那么这个神秘的Activity到底是何方神圣呢?
我想我不说大家也应该猜到了,这个Activity肯定是存在与DocumentsUI中,因为上面我们已经说到过了,DocumentUI是整个下载系统的视图层。那么下面就转战我们这一小节的主角DocumentsUI。
通过DocumentsUI的AndroidManifest文件知道,接受“下载”发出的Intent的Activity就是上面的DocumentsActivity,它的路径是
/frameworks/base/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
我将DocumentsActivity的启动流程分两步来分析
- 初始化状态信息
- 查询和显示对应的数据
初始化状态信息的流程如下:
在onCreate方法中会调用buildDefaultState方法来初始化mState对象。State是专门存储状态信息的
223 private void buildDefaultState() {224 mState = new State();225226 final Intent intent = getIntent();227 final String action = intent.getAction();228 if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {229 mState.action = ACTION_OPEN;230 } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {231 mState.action = ACTION_CREATE;232 } else if (Intent.ACTION_GET_CONTENT.equals(action)) {233 mState.action = ACTION_GET_CONTENT;234 } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) {235 mState.action = ACTION_OPEN_TREE;236 } else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) {237 mState.action = ACTION_MANAGE;238 }239240 if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {241 mState.allowMultiple = intent.getBooleanExtra(242 Intent.EXTRA_ALLOW_MULTIPLE, false);243 }244245 if (mState.action == ACTION_MANAGE) {246 mState.acceptMimes = new String[] { "*/*" };247 mState.allowMultiple = true;248 } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {249 mState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);250 } else {251 mState.acceptMimes = new String[] { intent.getType() };252 }253254 mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);255 mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);256 mState.showAdvanced = mState.forceAdvanced257 | LocalPreferences.getDisplayAdvancedDevices(this);258259 if (mState.action == ACTION_MANAGE) {260 mState.showSize = true;261 } else {262 mState.showSize = LocalPreferences.getDisplayFileSize(this);263 }264 }
由于前面传入的action为“DocumentsContract.ACTION_MANAGE_ROOT”,这里会走236行将mState.action 设置为 ACTION_MANAGE
在Sate类中的restored变量初始值为false,所以在onCreate方法中会走下面这段代码
211 if (!mState.restored) {212 if (mState.action == ACTION_MANAGE) {213 final Uri rootUri = getIntent().getData();214 new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());215 } else {216 new RestoreStackTask().execute();217 }218 } else {219 onCurrentDirectoryChanged(ANIM_NONE);220 }
通过调用RestoreRootTask来将当面信息保存下来,接着调用onRootPicked来对需要显示的内容做相应判断。
在onRootPicked中又会启动另一个异步任务PickRootTask,它主要作用是通过intent中的data信息来构建DocumentInfo的对象,该对象中主要保存一下字段
56 public String authority;57 public String documentId;58 public String mimeType;59 public String displayName;60 public long lastModified;61 public int flags;62 public String summary;63 public long size;64 public int icon;
这里的authority现在的值为"com.android.providers.downloads.documents",documentId的值为"downloads"
获得了以上信息后,PickRootTask的任务差不多就完成了,接着它会调用onCurrentDirectoryChanged来告诉DocumentsUI,“有人要显示所有下载的信息,我这边的信息处理完了你可以去查询和显示下载信息了”
查询和显示对应的数据流程如下
首先在onCreateView方法中初始化界面布局,接着在onActivityCreated中初始化Adapter和异步数据加载器,最后将从数据库取出来的数据与Adapter进行绑定。
这里我们重点看异步查询数据部分
mCallbacks = new LoaderCallbacks<DirectoryResult>() {262 @Override263 public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {264 final String query = getArguments().getString(EXTRA_QUERY);265266 Uri contentsUri;267 switch (mType) {268 case TYPE_NORMAL:269 contentsUri = DocumentsContract.buildChildDocumentsUri(270 doc.authority, doc.documentId);271 if (state.action == ACTION_MANAGE) {272 contentsUri = DocumentsContract.setManageMode(contentsUri);273 }274 return new DirectoryLoader(275 context, mType, root, doc, contentsUri, state.userSortOrder);276 //部分代码省略289 }290 }291292 @Override293 public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {294 if (!isAdded()) return;295296 mAdapter.swapResult(result);297 //部分代码省略321322 mLastSortOrder = state.derivedSortOrder;323 }324325 @Override326 public void onLoaderReset(Loader<DirectoryResult> loader) {327 mAdapter.swapResult(null);328 }329 };
在之前的讲述中知道state.actio的值为ACTION_MANAGER,onCreateLoader会走271行代码,然后返回一个DirectoryLoader来进行数据的查询。当DirectoryLoader查询完数据后系统会回调onLoadFinished方法,最后通过
mAdapter.swapResult(result);来将数据与Adapter绑定。Adapter有了数据的更新自然就会去更新界面,那么此时从打开“下载”app到整个界面解显示就结束了。最终界面如下图:
总结一下,点击“下载”app主要经历一下一个步骤:
- 从DownloadList跳转到DocumentsActivity
- 保存需要显示的内容信息
- 通过DirectoryLoader完成异步查询数据
- 显示数据
Android L 源代码在线查看http://androidxref.com/5.1.0_r1/
- Android Download机制详解(一)DocumentUI部分
- Android Download机制详解(一)DocumentUI部分
- Android Download机制详解
- android的binder机制研究一(C++部分)
- Android事件分发机制详解(一)
- Android 广播内部机制详解(一)
- android 事件分发机制详解(一)
- Android - Download(下载) 项目 详解
- LoaderManager使用详解(一)---Android中的Loaders机制
- 【Android】Handler机制源码详解(一)
- Android异步机制详解一:THread+Handle
- Android事件分发机制详解(一)
- RunTime机制详解(一)
- android Handle机制(一)
- android主题机制(一)
- Android Vold机制(一)
- android binder机制(一)
- Android绘图机制(一)
- android开发技巧——仿新版QQ锁屏下弹窗
- 万能适配器MyBaseAdapter
- 连通图的割点、割边(桥)、块、缩点,有向图的强连通分量
- DNS服务相关概念
- 数据库startup启动不起来了。报错ORA-01172
- Android Download机制详解(一)DocumentUI部分
- Mac OS 升级svn客户端
- TextView字体颜色选择器
- pthread_join和pthread_detach详解
- Jsp内置对象及EL表达式的使用
- Tomcat
- wordpress第三天
- [Elasticsearch] 常用查询和操作总结
- libc.so.6被误删除后的急救