前面一讲解了Gallery启动Activity以及界面如何绘制,现在开始讲解启动流程的代码逻辑。 
GalleryActivity的onCreate方法中调用initializeByIntent()方法,顾名思义这个方法就是根据Intent事件来初始化的。

 1 private void initializeByIntent() {
 2         Intent intent = getIntent();
 3         String action = intent.getAction();
 4
 5         if (Intent.ACTION_GET_CONTENT.equalsIgnoreCase(action)) {
 6             startGetContent(intent);
 7         } else if (Intent.ACTION_PICK.equalsIgnoreCase(action)) {
 8            ......
 9         } else if (Intent.ACTION_VIEW.equalsIgnoreCase(action)
10                 || ACTION_REVIEW.equalsIgnoreCase(action)){
11             startViewAction(intent);
12         } else {
13             //我们从桌面启动应用时Intent的Action是android.intent.action.MAIN,所以会走到这一步
14             startDefaultPage();
15         }
16     }

我们看一下这个方法,它是通过Bundle来传输数据

1 public void startDefaultPage() {
2         ......
3         Bundle data = new Bundle();
4         data.putString(AlbumSetPage.KEY_MEDIA_PATH,
5                 getDataManager().getTopSetPath(DataManager.INCLUDE_ALL));
6         getStateManager().startState(AlbumSetPage.class, data);
7         ......
8     }

上面这个方法涉及的东西很多,AlbumSetPage继承自ActivityState,显示所有相册缩略图的页面,也就是进入Gallery显示的第一个界面。DataManager是数据管理,给每个界面提供数据源。StateManager是用来管理ActivityState的,控制每个界面的创建和销毁。

首先讲一下ActivityState,它是一个抽象类,它的具体实现的子类有AlbumSetPage(显示所有相册缩略图的页面),AlbumPage(显示单个相册所有照片缩略图的页面),ManageCachePage(缓存管理页面),PhotoPage(单张照片),SlideShowPage(滑屏页面)。进入Gallery显示的是AlbumSetPage,它是由多个相册组成的;然后点击某一相册显示的AlbumPage,它由该相册的所有缩略图组成;再点击其中某一张图片显示的就是PhotoPage。这些页面的切换都是由StateManager来管理。页面切换示意图如下

Gallery中切换界面是不会跳转Activity的,因为并没有对应每个界面的Activity,那怎么更新界面的?其实就是StateManager通过栈(stack)来管理要显示的界面,每个界面都是一个ActivityState类,切换界面做的就是stack的入栈和出栈操作,所以我们可以把ActivityState想象成是一个Activity。

然后讲一下DataManager,看上述代码,Bundle的value是getDataManager().getTopSetPath(DataManager.INCLUDE_ALL)。
getDataManager()是调用GalleryAppImpl的方法

 1 @Override
 2     public synchronized DataManager getDataManager() {
 3         if (mDataManager == null) {
 4             //实例化一个DataManager,并且传入GalleryAppImpl的引用,然后获取主线程的Handler
 5             mDataManager = new DataManager(this);
 6             //初始化数据源
 7             mDataManager.initializeSourceMap();
 8         }
 9         return mDataManager;
10     }

现在看一下initializeSourceMap方法

 1 public synchronized void initializeSourceMap() {
 2         if (!mSourceMap.isEmpty()) return;
 3         //addSource就是把所有数据源都添加给mSourceMap,mSourceMap是一个HashMap,其key是各数据源的名称,value就是各数据源的对象。
 4         // 这个添加顺序很重要
 5         addSource(new LocalSource(mApplication));
 6         addSource(new PicasaSource(mApplication));
 7         addSource(new ComboSource(mApplication));
 8         addSource(new ClusterSource(mApplication));
 9         addSource(new FilterSource(mApplication));
10         addSource(new SecureSource(mApplication));
11         addSource(new UriSource(mApplication));
12         addSource(new SnailSource(mApplication));
13
14         if (mActiveCount > 0) {
15             for (MediaSource source : mSourceMap.values()) {
16                 source.resume();
17             }
18         }
19     }

数据源如上述代码所示分为七种,由一个HashMap类型的mSourceMap来管理。它们都是继承自MediaSource抽象类,数据源的作用就是给前面讲的ActivityState类型提供缩略图。至于ActivityState和数据源之间怎么交互的后面再讲。

接着之前的代码分析,data最终的key是AlbumSetPage.KEY_MEDIA_PATH,value值就是”/combo/{/local/all,/picasa/all}”,见如下代码

 1 data.putString(AlbumSetPage.KEY_MEDIA_PATH,
 2                 getDataManager().getTopSetPath(DataManager.INCLUDE_ALL));
 3
 4 public String getTopSetPath(int typeBits) {
 5
 6         switch (typeBits) {
 7             case INCLUDE_IMAGE: return TOP_IMAGE_SET_PATH;
 8             case INCLUDE_VIDEO: return TOP_VIDEO_SET_PATH;
 9             case INCLUDE_ALL: return TOP_SET_PATH;
10             case INCLUDE_LOCAL_IMAGE_ONLY: return TOP_LOCAL_IMAGE_SET_PATH;
11             case INCLUDE_LOCAL_VIDEO_ONLY: return TOP_LOCAL_VIDEO_SET_PATH;
12             case INCLUDE_LOCAL_ALL_ONLY: return TOP_LOCAL_SET_PATH;
13             default: throw new IllegalArgumentException();
14         }
15     }
16
17 private static final String TOP_SET_PATH = "/combo/{/local/all,/picasa/all}";

然后将此data传给AlbumSetPage并启动此页面

1 getStateManager().startState(AlbumSetPage.class, data);

在讲startState方法之前,我先讲一下StateManager类,它最主要的一点就是持有一个栈来管理ActivityState和上面的data数据

 1 private Stack<StateEntry> mStack = new Stack<StateEntry>();
 2
 3 private static class StateEntry {
 4         public Bundle data;
 5         public ActivityState activityState;
 6
 7         public StateEntry(Bundle data, ActivityState state) {
 8             this.data = data;
 9             this.activityState = state;
10         }
11     }

startState方法所做的就是根据创建一个StateEntry并且push到mStack栈中

 1 //这里的klass就是AlbumSetPage类,data就是传入的数据
 2 public void startState(Class<? extends ActivityState> klass,
 3             Bundle data) {
 4         Log.v(TAG, "startState " + klass);
 5         //获取AlbumSetPage对象
 6         ActivityState state = null;
 7         try {
 8             state = klass.newInstance();
 9         } catch (Exception e) {
10             throw new AssertionError(e);
11         }
12         //如果栈不为空,将栈顶的ActivityState暂停
13         if (!mStack.isEmpty()) {
14             ActivityState top = getTopState();
15             top.transitionOnNextPause(top.getClass(), klass,
16                     StateTransitionAnimation.Transition.Incoming);
17             if (mIsResumed) top.onPause();
18         }
19         ......
20         //根据mActivity和data初始化AlbumSetPage
21         state.initialize(mActivity, data);
22         //入栈
23         mStack.push(new StateEntry(data, state));
24         //下面两个方法就关键了,用来显示界面的
25         state.onCreate(data, null);
26         if (mIsResumed) state.resume();
27     }

这里的state是指AlbumSetPage,我们查看一下AlbumSetPage的onCreate方法

1 @Override
2     public void onCreate(Bundle data, Bundle restoreState) {
3         super.onCreate(data, restoreState);
4         //初始化View
5         initializeViews();
6         //初始化数据
7         initializeData(data);
8         ......
9     }

我们接着看下怎么初始化View的

 1 private void initializeViews() {
 2         ......
 3         //mConfig是用来设置SlotView的参数,而SlotView就是一个相册
 4         mConfig = Config.AlbumSetPage.get(mActivity);
 5         //实例化一个SlotView
 6         mSlotView = new SlotView(mActivity, mConfig.slotViewSpec);
 7         //mAlbumSetView是mSlotView的渲染器,控制mSlotView的显示
 8         mAlbumSetView = new AlbumSetSlotRenderer(
 9                 mActivity, mSelectionManager, mSlotView, mConfig.labelSpec,
10                 mConfig.placeholderColor);
11         //将mAlbumSetView设置给mSlotView
12         mSlotView.setSlotRenderer(mAlbumSetView);
13         //监听SlotView事件,根据手势操作做出相应的响应,这个监听事件的原理后面再分析
14         mSlotView.setListener(new SlotView.SimpleListener() {
15             @Override
16             public void onDown(int index) {
17                 AlbumSetPage.this.onDown(index);
18             }
19
20             @Override
21             public void onUp(boolean followedByLongPress) {
22                 AlbumSetPage.this.onUp(followedByLongPress);
23             }
24
25             @Override
26             public void onSingleTapUp(int slotIndex) {
27                 AlbumSetPage.this.onSingleTapUp(slotIndex);
28             }
29
30             @Override
31             public void onLongTap(int slotIndex) {
32                 AlbumSetPage.this.onLongTap(slotIndex);
33             }
34         });
35         ......
36         //把这个SlotView作为一个子控件传给GLView,mRootPane是GLView类
37         mRootPane.addComponent(mSlotView);
38     }

最后看一下初始化数据,数据都是通过DataManger来管理,至于如何加载后面在分析。

 1 private void initializeData(Bundle data) {
 2         //获取data传入的value
 3         String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH);
 4         //获取MediaSet,前面讲了每个ActivityState页面都需要一个数据源MediaSource来获取显示数据,而MediaSource是由MediaObject组成,MediaObject相当于MediaSource的单位,MediaSet就是一个MediaObject的子类,管理一组媒体数据
 5         mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath);
 6         //mSelectionManager用于管理选择事件
 7         mSelectionManager.setSourceMediaSet(mMediaSet);
 8         //mAlbumSetDataAdapter类似于桥梁来连接页面和数据源
 9         mAlbumSetDataAdapter = new AlbumSetDataLoader(
10                 mActivity, mMediaSet, DATA_CACHE_SIZE);
11         //设置数据加载的监听接口
12         mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener());
13         mAlbumSetView.setModel(mAlbumSetDataAdapter);
14     }

转载于:https://www.cnblogs.com/zhao-shan/p/9838352.html

Android 7.0 Gallery图库源码分析2 - 分析启动流程相关推荐

  1. Android中mesure过程详解 (结合Android 4.0.4 最新源码)

    如何遍历并绘制View树?之前的文章Android中invalidate() 函数详解(结合Android 4.0.4 最新源码)中提到invalidate()最后会发起一个View树遍历的请求,并通 ...

  2. Android中layout过程详解 (结合Android 4.0.4 最新源码)

    上一篇文章Android中mesure过程详解 (结合Android 4.0.4 最新源码)介绍了View树的measure过程,相对与measure过程,本文介绍的layout过程要简单多了,正如l ...

  3. 12.源码阅读(app启动流程-android api 26)

    activity的启动流程之前已经通过源码了解了,那么app的启动流程是怎样的,从我们按下app的图标,到应用启动起来显示出画面,中间都经历了什么? 安卓是基于java的,所以和java有一定的相似性 ...

  4. Android 10.0 PackageManagerService(一)工作原理及启动流程-[Android取经之路]

    摘要:PackageManagerService是Android系统核心服务之一,在Android中的非常重要,主要负责APK.jar包等的管理. 阅读本文大约需要花费50分钟. 文章的内容主要还是从 ...

  5. kotlin coroutine源码解析之Job启动流程

    目录 Job启动流程 launch流程分析 父子Job关联分析 结论 Job启动流程 job启动流程,我们先从一段最简单使用协程的代码开始,进行代码跟跟踪,顺便引出几个关键的概念,在后面章节里面去单独 ...

  6. 2022全新米酷影视V7.0.3网站源码+带插口分析

    简介: 更新说明: 1:提升主页热映强烈推荐CSS款式 2:提升影视制作目录CSS款式 3:修复观看历史题目太长自动换行难题 4:提升大牌明星网页页面CSS款式 5:提升明星搜索网页页面 米酷影视升级 ...

  7. android 10.0 在系统源码下生成jks系统签名文件

    在系统开发中,会遇到在app在线升级的时候,会升级失败,由于app自己用自己的签名文件签名的 所以会和系统签名文件不一样,导致会出现一些问题 所以为了解决这一个问题 就得使用系统生成的签名文件 给ap ...

  8. ThinkPHP5.0源码学习之框架启动流程

    ThinkPHP5框架的启动流程图如下: ThinkPHP5的启动流程按照文件分为三步: 1.请求入口(public/index.php) 2.框架启动(thinkphp/start.php) 3.应 ...

  9. Android 11.0 PackageManagerService(一)工作原理和启动流程

    1. 概述 PackageManagerService是Android系统核心服务之一,也是Android中最常用的服务之一.它主要负责的工作如下: 1.  解析AndroidManifest.xml ...

最新文章

  1. Servlet,过滤器,监听器,拦截器的区别
  2. Java线程池使用与原理
  3. The user specified as a definer ('root'@'%') does not exist
  4. Python模块和包
  5. awk、变量、运算符、if多分支
  6. 贾扬清撰文详解Caffe2:从强大的新能力到入门上手教程
  7. esp32 怎么分配freertos 堆栈大小_深度解剖~ FreeRtos阅读笔记2 任务创建、内核链表初始化...
  8. python实现抓取网页上的内容并发送到邮箱
  9. 于连生性聪颖的飞鸽传书
  10. android R vendor.boot-hal-1-1启动失败问题分析
  11. springBoot跨域解决
  12. javascript 时间类型 Date
  13. mqtt发布json数据_微服务实战:从架构到发布(一)
  14. 企业税银数据深度分析(上)
  15. oracle和Linux能兼容吗,Oracle基于Linux 7下的安装
  16. 递归处理二叉树总结(附leetcode题)
  17. 服务器不在工作_十次方:服务器租用一般有哪些品牌
  18. 全面了解量化风险管理
  19. PS 复制图层使用
  20. python在线编辑器可视化_海龟编辑器(Python编辑器)

热门文章

  1. JAVA 两个简单的抽奖算法
  2. Java Web学习(六)HttpServletRequest(客户端请求)
  3. .net 如何设置和检索特性信息(attribute)
  4. Raspbian安装Opencv3
  5. NYOJ--1236--挑战密室(第八届河南省程序设计大赛)
  6. 内存管理之slab分配器
  7. 20135231 —— 第六周任务总结报告
  8. ios动态获取UILabel的高度和宽度
  9. 实验五 操作系统之存储管理
  10. centos下wget时提示unable to resolve host address ...