Android Download机制详解(一)DocumentUI部分

2023-05-16

在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的入口。它的入口一般有两个:

  1. Launcher上的“下载”app
  2. 被其他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;
18
19import android.app.Activity;
20import android.content.Intent;
21import android.os.Bundle;
22import android.provider.DocumentsContract;
23
24import com.android.providers.downloads.Constants;
25
26public class DownloadList extends Activity {
27    @Override
28    public void onCreate(Bundle icicle) {
29        super.onCreate(icicle);
30
31        // Trampoline over to new management UI
32        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的启动流程分两步来分析

  1. 初始化状态信息
  2. 查询和显示对应的数据

初始化状态信息的流程如下:

在onCreate方法中会调用buildDefaultState方法来初始化mState对象。State是专门存储状态信息的


223    private void buildDefaultState() {
224        mState = new State();
225
226        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        }
239
240        if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
241            mState.allowMultiple = intent.getBooleanExtra(
242                    Intent.EXTRA_ALLOW_MULTIPLE, false);
243        }
244
245        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        }
253
254        mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
255        mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
256        mState.showAdvanced = mState.forceAdvanced
257                | LocalPreferences.getDisplayAdvancedDevices(this);
258
259        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            @Override
263            public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
264                final String query = getArguments().getString(EXTRA_QUERY);
265
266                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 } 291 292 @Override 293 public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) { 294 if (!isAdded()) return; 295 296 mAdapter.swapResult(result); 297 //部分代码省略 321 322 mLastSortOrder = state.derivedSortOrder; 323 } 324 325 @Override 326 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主要经历一下一个步骤:

  1. 从DownloadList跳转到DocumentsActivity
  2. 保存需要显示的内容信息
  3. 通过DirectoryLoader完成异步查询数据
  4. 显示数据

 Android L 源代码在线查看http://androidxref.com/5.1.0_r1/

转载于:https://www.cnblogs.com/zqlxtt/p/4451949.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Download机制详解(一)DocumentUI部分 的相关文章

  • 使用DBFlow,如何加密已经存在的数据库?

    我正在使用 DBFlow 来处理项目中的数据库 并且我想对现有数据库进行加密 我知道我可能必须删除现有的未加密数据库并创建另一个加密数据库 我也知道我可以将 SQLCipher 与 DBFlow 一起使用 如上所述文档 https gith
  • 如何访问 Android 心率传感器原始数据? (反射光,不是心跳)

    心率传感器上的 android sdk 仅返回计算出的 bpm 我对此不感兴趣 我需要访问 Android 心率传感器原始数据 例如就反射值的强度而言将会很大 因为心率传感器基本上使用 LED 并测量随时间变化的反射率 如果可能 访问由任何
  • 升级到最新支持库后Android JACK编译器错误

    Android Studio 2 2 3 Windows 10 64位 构建工具版本 25 Android Gradle插件版本2 2 3 升级到最新的支持库 从 23 4 0 到 25 1 0 并更改编译版本 从 23 到 25 后 我收
  • Android Camera.takePicture() 有时不返回?

    我正在编写一个Android 拍照应用程序 该代码在 onPreviewFrame byte data Cameracamera 中从预览中获取帧后进行一些处理 问题在于 android hardware Camera 的函数 takePi
  • VOIP通话录音

    我正在开发一个在 android 中录制 VOIP 通话的项目 我没有找到任何解决方案 有很多应用程序支持手机上的 VOIP 录音 我找不到任何教程和帮助 立方体通话记录器 https play google com store apps
  • CoordinatorLayout 和 ImageView 在滚动时调整宽度的问题

    我正在尝试放置一个ImageView in a CollapsingToolbarLayout它在加载时占据整个屏幕 并且当您滚动内容时 16x9 分辨率图像宽度会调整大小 直到图像占据屏幕的整个宽度 那时 我希望图像具有视差app lay
  • 在 NFC 标签扫描期间,onNewIntent() 内的intent.getAction() 为 null

    这是我第一次使用 NFC 标签 我在清单中声明了 NFC 扫描活动
  • 什么是 Android 测试协调器?

    谷歌最近发布了Android测试支持库1 0 读完后overview https android developers googleblog com 2017 07 android testing support library 10 is
  • Toast 消息消失后​​完成活动吗?

    有谁知道 是否有可能对 Toast 消息执行某些操作 在我的情况下完成活动 将被关闭 您只需创建一个Thread持续时间只要Toast显示 然后您就可以完成您的Activity public void onCreate Bundle sav
  • 模拟器无法加载

    我正在使用 hello android 教程并通过 eclipse 创建 avd 启动模拟器时不使用图像 它只是显示一个黑色的后屏 中间有 ANDROID 字样 并且在 ANDROID 字样的末尾有一个闪烁的光标 我已按照 T 的步骤安装
  • Android 操作项上的通知徽章

    我想在操作栏中放置的购物车图像上添加一个通知徽章 并以编程方式操作它 有帮助吗 您可以显示自定义MenuItem on ActionBar通过创建一个custom layout for MenuItem 要设置自定义布局 您必须使用菜单项属
  • 使用 Proguard 通过 Dropbox.com 库混淆 Android 应用程序

    我刚刚创建了一个需要 Dropbox com API 库的 Android 应用程序 我现在尝试在 发布 模式下构建应用程序 并希望在代码上运行混淆器以对其进行混淆 但是 每当我尝试运行 Proguard 时 都会收到以下错误 Progua
  • 以 HTML 格式发送电子邮件

    我想发送 HTML 格式的电子邮件 如下图所示 我怎样才能做到这一点 请帮我 提前致谢 String body new String table tr td br header td tr br br Get b Best Score b
  • Android 中 Activity 之间的 3D 动画

    How to create animation between two Activity look like As Screen shot in android 搜索jazzyviewpager 这是link https github co
  • 了解应用程序在后台时何时收到 Firebase 消息

    我知道这个标题有同样的问题 但不幸的是它没有得到正确的回答 它被接受了 here https stackoverflow com questions 37711082 how to handle notification when app
  • Android计算两个日期之间的天数

    我编写了以下代码来查找两个日期之间的天数 startDateValue new Date startDate endDateValue new Date endDate long diff endDateValue getTime star
  • 调试android数据绑定?

    谁能告诉我如何调试或找到数据绑定生成的代码 从this https www youtube com watch v NBbeQMOcnZ0链接我发现它生成了所需的代码 我猜您正在寻找自动生成的绑定 java 文件 我也在寻找他们 最后我在这
  • 在数组列表中过滤 Filterable 不取消之前的过滤

    我看过过滤器方法文档 其中显示调用过滤器会取消所有先前未执行的过滤请求 并发布一个稍后将执行的新过滤请求 但我收到的实际回调有些不同 在我的实现中 它不会取消先前的过滤器请求并调用publishResults 最近一次搜索条件后的上一次搜索
  • 如何从DataSource.Factory获取数据

    我必须调用此方法才能获取所有人员 我根本无法修改这个方法 Query SELECT FROM PERSON TABLE ORDER BY NAME DESC abstract fun getElements DataSource Facto
  • 如何用LoaderManager自动重新查询

    我有一个应用程序显示来自 SQLite DB 的数据 并且数据不断变化 所以显然 我认为我应该使用 LoaderManager 来显示数据 我读过一些关于将 LoaderManager 与 SQLite 结合使用的内容 然后看到了亚历克斯

随机推荐

  • 如何学习计算机编程语言

    关于如何学习计算机编程语言 xff08 C C 43 43 Java Python PHP xff09 1 计算机编程语言是我们和计算机交流信息的载体 xff0c 我们通过它和计算机 说话 xff0c 计算机听到我们说的话 xff0c 领会
  • WebRTC音视频同步

    这两篇文章 xff0c 可以直接去看 xff1b WebRTC音视频同步机制实现分析 https www jianshu com p 3a4d24a71091 WebRTC音视频同步分析 https blog csdn net lincai
  • nginx编译,修改日志路径

    1 configure without http rewrite module 2 修改objs ngx auto config h ifndef NGX PID PATH define NGX PID PATH 34 var logs n
  • 什么是MySQL执行计划

    要对执行计划有个比较好的理解 xff0c 需要先对MySQL的基础结构及查询基本原理有简单的了解 MySQL本身的功能架构分为三个部分 xff0c 分别是 应用层 逻辑层 物理层 xff0c 不只是MySQL xff0c 其他大多数数据库产
  • SPSS详细操作:生存资料的Cox回归分析

    SPSS详细操作 xff1a 生存资料的Cox回归分析 一 问题与数据 某研究者拟观察某新药的抗肿瘤效果 xff0c 将70名肺癌患者随机分为两组 xff0c 分别采用该新药和常规药物进行治疗 xff0c 观察两组肺癌患者的生存情况 xff
  • 生产者和消费者模型

    生产者和消费者模型 1 什么是生产者和消费者模型 生产者消费者模型具体来讲 xff0c 就是在一个系统中 xff0c 存在生产者和消费者两种角色 xff0c 他们通过内存缓冲区进行通信 xff0c 生产者生产消费者需要的资料 xff0c 消
  • 八大排序算法源码 + 耗时长度比较

    八大排序算法的排序时间长度的比较 xff0c 测试数据10000000时部分结果如下 输入测试数据长度 10000000 数据初始化中 数据初始化完成 堆排序用时 8秒 499毫秒 快速排序用时 22秒 35毫秒 归并排序用时 34秒 47
  • intellij idea - Project Structure 项目结构详解(简单明了)

    IDEA Project Structure 设置 可以点击 按钮 xff0c 或者使用快捷键 Ctrl 43 Shift 43 Alt 43 S 打开 Project Structure 如下如所示 xff1b 项目的左侧面板 Proje
  • Linux下如何查看计算机的配置信息(cpu物理个数、几核)

    查看物理CPU的个数 cat proc cpuinfo grep 34 physical id 34 sort uniq wc l 查看逻辑CPU的个数 cat proc cpuinfo grep 34 processor 34 wc l
  • python的cfg是什么模块_python操作cfg配置文件方式

    cfg文件一般是程序运行的配置文件 xff0c python为读写常见配置文件提供了一个ConfigParser模块 xff0c 所以在python中解析配置文件相当简单 xff0c 下面就举例说明一下具体的操作方法 写文件代码 xff1a
  • 团队价值观五个字_一个优秀的团队应该具有的价值观

    第一 xff1a 树立全局观念 每个员工都应该树立全局观念 xff0c 一个人要想在工作中快速成长 xff0c 就必须把自己的工作纳入全局 xff0c 依靠集体的力量来提升自己 xff1b 每个员工都应该理解并支持企业的整体目标 xff0c
  • matlab中的varargin用法,MATLAB中的nargin与varargin

    varargin 1 定义 xff1a varargin指代的是一个函数的变输入参数列表 所谓的变输入参数列表 xff1a 即varargin可以等价于任意不定个数的输入参数 例如 xff0c F是一个函数 xff0c F a 可以用F v
  • linux和windows局域网连接网络,linux与windows局域网互访

    8种机械键盘轴体对比 本人程序员 xff0c 要买一个写代码的键盘 xff0c 请问红轴和茶轴怎么选 xff1f 场景 做无人机地面站时 xff0c 地面站需要检测数据做实时飞行跟踪和轨迹预测 但是比赛场地设备太多 xff0c 信号嘈杂 x
  • 华为鸿蒙基金,基金筛选:华为鸿蒙新版即将揭开面纱

    如果有人拧熄了灯塔 xff0c 我们怎么航行 xff1f 近日这句由华为创始人任正非发出的声音成为了眼下华为内部思考最多的话题 尤其作为华为 三驾马车 之一的消费者业务部门 xff0c 在接连经受了外部挫折后 xff0c 如何持续前行 xf
  • 360极速浏览器网页保护色

    方法一 xff1a 360浏览器的 扩展中心 有一个 绿色眼睛 的插件 xff1b 但是感觉一般 xff0c 不够彻底 xff1b 方法二 xff1a 360急速浏览器是基于开源Chrome浏览器修改的 xff0c 所以可以直接用Chrom
  • css样式表的标签,CSS样式表标签.doc

    CSS样式表标签 CSS样式表标签选择符大全 一 类型选择符 以下是代码片段 xff1a body font size 12px P color blue 指对网页中已有的标签类型作为名称的选择符 xff0c 如上表示 xff1a body
  • 系统推送服务器搭建,利用云推送服务搭建自己的消息通知系统

    define 39 appid 39 39 1009 39 APP ID define 39 appsec 39 39 c2910c5bcc905a5729fd 39 APP SECRET tokenfile 61 fopen 34 tok
  • 如何修改apk服务器,如何修改apk连接服务器地址

    如何修改apk连接服务器地址 内容精选 换一换 在移动设备上正确安装APP后 xff0c 就可以通过APP登录NetEco服务器 创建弹性云服务器 xff0c 请参见 弹性云服务器用户指南 该弹性云服务器用于连接云数据库RDS实例 xff0
  • 程序员、架构师、技术经理、技术总监和CTO有啥区别?

    http www javaranger com archives 1997 程序员 程序员 xff0c 英文名coder programmer xff0c 大家常自嘲叫码农的阶段 这个角色职责是把需求或产品实现为用户可用的软件产品 此职位为
  • Android Download机制详解(一)DocumentUI部分

    在Android中Google为我们集成了一套十分便利的Download机制 xff0c 用来下载网络上的资源文件 以此省去了我们编写和维护大量与Download相关的代码 组成 Android中Download由三个部分组成 xff1a