Android 7.0 Gallery图库源码分析2 - 分析启动流程

追风赶月莫停留,平芜尽处是春山。这篇文章主要讲述Android 7.0 Gallery图库源码分析2 - 分析启动流程相关的知识,希望能为你提供帮助。
前面一讲解了Gallery启动Activity以及界面如何绘制,现在开始讲解启动流程的代码逻辑。 
GalleryActivity的onCreate方法中调用initializeByIntent()方法,顾名思义这个方法就是根据Intent事件来初始化的。

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

我们看一下这个方法,它是通过Bundle来传输数据
1 public void startDefaultPage() { 2...... 3Bundle data = https://www.songbingjia.com/android/new Bundle(); 4data.putString(AlbumSetPage.KEY_MEDIA_PATH, 5getDataManager().getTopSetPath(DataManager.INCLUDE_ALL)); 6getStateManager().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 2public synchronized DataManager getDataManager() { 3if (mDataManager == null) { 4//实例化一个DataManager,并且传入GalleryAppImpl的引用,然后获取主线程的Handler 5mDataManager = new DataManager(this); 6//初始化数据源 7mDataManager.initializeSourceMap(); 8} 9return mDataManager; 10}

现在看一下initializeSourceMap方法
1 public synchronized void initializeSourceMap() { 2if (!mSourceMap.isEmpty()) return; 3//addSource就是把所有数据源都添加给mSourceMap,mSourceMap是一个HashMap,其key是各数据源的名称,value就是各数据源的对象。 4// 这个添加顺序很重要 5addSource(new LocalSource(mApplication)); 6addSource(new PicasaSource(mApplication)); 7addSource(new ComboSource(mApplication)); 8addSource(new ClusterSource(mApplication)); 9addSource(new FilterSource(mApplication)); 10addSource(new SecureSource(mApplication)); 11addSource(new UriSource(mApplication)); 12addSource(new SnailSource(mApplication)); 13 14if (mActiveCount > 0) { 15for (MediaSource source : mSourceMap.values()) { 16source.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, 2getDataManager().getTopSetPath(DataManager.INCLUDE_ALL)); 3 4 public String getTopSetPath(int typeBits) { 5 6switch (typeBits) { 7case INCLUDE_IMAGE: return TOP_IMAGE_SET_PATH; 8case INCLUDE_VIDEO: return TOP_VIDEO_SET_PATH; 9case INCLUDE_ALL: return TOP_SET_PATH; 10case INCLUDE_LOCAL_IMAGE_ONLY: return TOP_LOCAL_IMAGE_SET_PATH; 11case INCLUDE_LOCAL_VIDEO_ONLY: return TOP_LOCAL_VIDEO_SET_PATH; 12case INCLUDE_LOCAL_ALL_ONLY: return TOP_LOCAL_SET_PATH; 13default: 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 { 4public Bundle data; 5public ActivityState activityState; 6 7public StateEntry(Bundle data, ActivityState state) { 8this.data = https://www.songbingjia.com/android/data; 9this.activityState = state; 10} 11}

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

这里的state是指AlbumSetPage,我们查看一下AlbumSetPage的onCreate方法
1 @Override 2public void onCreate(Bundle data, Bundle restoreState) { 3super.onCreate(data, restoreState); 4//初始化View 5initializeViews(); 6//初始化数据 7initializeData(data); 8...... 9}

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

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

【Android 7.0 Gallery图库源码分析2 - 分析启动流程】 







    推荐阅读