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     }
  • 相关阅读:
    SCILAB简介[z]
    UG OPEN API编程基础 2约定及编程初步
    Office 2003与Office 2010不能共存的解决方案
    UG OPEN API 编程基础 3用户界面接口
    NewtonRaphson method
    UG OPEN API编程基础 13MenuScript应用
    UG OPEN API编程基础 14API、UIStyler及MenuScript联合开发
    UG OPEN API编程基础 4部件文件的相关操作
    UG OPEN API编程基础 1概述
    16 UG Open的MFC应用
  • 原文地址:https://www.cnblogs.com/zhao-shan/p/9838352.html
Copyright © 2011-2022 走看看