zoukankan      html  css  js  c++  java
  • Android 7.0 Gallery图库源码分析2

    前面一讲解了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     }
  • 相关阅读:
    Java并发编程(1)-Java内存模型
    Java源码解读(一) 8种基本类型对应的封装类型
    怎样修改织梦网站的favicon图标
    友情链接:图片链接或文字链接
    FCKeditor 添加行距、字体功能 (转载)
    如何解决织梦DedeCMS后台模块管理列表不显示
    制作兼容各种版本浏览器的新闻图片焦点切换效果
    织梦添加站内搜索
    织梦友情链接正确的调用方法和技巧
    织梦后台添加友情链接的方法(flink标签)
  • 原文地址:https://www.cnblogs.com/zhao-shan/p/9838352.html
Copyright © 2011-2022 走看看