1. Gallery主要的功能是实现本地存储器,MTP存储器和网络中的媒体(图像和视频)的浏览,
显示,操作(删除,分享,合成,选择和缩放等)。
下面的图来描述Gallery的职责:
Data Manager: 管理数据源,数据源包括: Uri连接数据,本地数据,Gmail同步数据,MTP传输数据,排序后的数据,过滤后的数据,加密数据,由客户自己添加的的数据,只包含一个资源的数据。这些数据源都有共同的基类: MediaSource。数据源由DataManager.java类负责管理。
显示的界面有:AlbumSetPage(相册缩略图), AlbumPage(单个相册的照片缩略图),PhotoPage(单个相片缩略图)。这些界面的父类为ActivityState.java,界面切换由StateManager.java负责。
Gallery常见浏览模式有:
1.AlbumSetPage模式: 相册集模式,即用户进入Gallery应用首先看到的相册模式,相册一般把相册集合的第一张照片作为封面图,在SD,内置内存卡,有图片和视频就会显示出来,那么依据什么来划分图像文件属于同一个相册集,相同目录和同样类型的图像文件属于同一个相册。
2.AlumPage模式: 点击了某个相册,进入AlbumPage模式,即包含一个目录的所有image 和video文件。此模式下可以浏览一个相册集所有的图像文件。
3.photoPage模式: 浏览相片和播放影片模式,这里具体到MediaItem。 点击某个图像文件,如果是相片用photo view来浏览,是video
文件则需要调用播放器来播放视频。 注意: 当AlbumSetPage只有一个item时,点击相册集会直接进入幻灯片模式。
图片浏览界面切换源码分析:
点击Gallery图标默认的界面是进入AlbumSetPage显示的界面,Gallery为主要界面的入口点。所有先从Gallery这个类来分析代码:
进入AlbumSetPage图库模式
protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.main); // 主界面 if (savedInstanceState != null) { getStateManager().restoreFromState(savedInstanceState); // 有保存状态信息 } else { initializeByIntent(); // 初始化处理action } }
private void initializeByIntent() { ... else { startDefaultPage();// 从桌面进入Gallery, 一般处理 } }
进入 startDefaultPage()方法:
public void startDefaultPage() { PicasaSource.showSignInReminder(this); Bundle data = new Bundle(); data.putString(AlbumSetPage.KEY_MEDIA_PATH, getDataManager().getTopSetPath(DataManager.INCLUDE_ALL)); // 包含Image 和Video文件
//add for DRM feature if (MediatekFeature.isDrmSupported()) { //when start default page, we query all drm media, any risk??? Log.d(TAG,"startDefaultPage:we query all drm media"); data.putInt(OmaDrmStore.DrmExtra.EXTRA_DRM_LEVEL, OmaDrmStore.DrmExtra.DRM_LEVEL_ALL); }//
if (MediatekFeature.isStereoDisplaySupported()) { if (null != getIntent().getExtras()) { data.putBoolean(StereoHelper.STEREO_EXTRA, getIntent().getExtras().getBoolean( StereoHelper.STEREO_EXTRA,false)); } }
// 切换到AlbumSetPage界面。 // 上面提到界面是用StateManager来管理的。 getStateManager().startState(AlbumSetPage.class, data); mVersionCheckDialog = PicasaSource.getVersionCheckDialog(this); if (mVersionCheckDialog != null) { mVersionCheckDialog.setOnCancelListener(this); } } |
进AlbumPage相册浏览模式
上面的getStateManager().startState(AlbumSetPage.class,data);
完成AlbumSetPager界面类的切换。下面来分析
StateManager.java 的startState方法
StateManager.java public void startState(Class<? extends ActivityState> klass, Bundle data) { ActivityState state = null; try { state = klass.newInstance(); // 新建一个实例 } catch (Exception e) { throw new AssertionError(e); } // 采用stack栈来管理页面逻辑切换。 if (!mStack.isEmpty()) { ActivityState top = getTopState(); top.transitionOnNextPause(top.getClass(), klass, StateTransitionAnimation.Transition.Incoming); if (mIsResumed) top.onPause(); } state.initialize(mActivity, data); mStack.push(new StateEntry(data, state)); // 压栈 state.onCreate(data, null); // AlbumSetPage.onCreate(); if (mIsResumed) state.resume(); }
|
…. 到这里就会显示相册集缩略图(AlbumSetPage), 这里注意的是;
AlbumSetPage并不是一个界面显示的类, 因为Gallery显示界面只有一个Activity,里面的界面都是用OpengL画出来的,而AlbumSetPage这是界面显示的逻辑部分,界面的切换跟数据逻辑绑定在一起的。
因为Gallery采用了MVC的架构。如图所示;
当我们点击某个相册时候,opengl就会检测到点击了那个相册,然后分发消息交给AlbumSetPage界面逻辑类来处理。
处理过程如下:
StateManager.java
public void startState(Class<? extends ActivityState> klass, Bundle data) { ActivityState state = null; try { state = klass.newInstance(); // 新建一个实例 } catch (Exception e) { throw new AssertionError(e); } // 采用stack栈来管理页面逻辑切换。 if (!mStack.isEmpty()) { ActivityState top = getTopState(); top.transitionOnNextPause(top.getClass(), klass, StateTransitionAnimation.Transition.Incoming); if (mIsResumed) top.onPause(); } state.initialize(mActivity, data); mStack.push(new StateEntry(data, state)); // 压栈 state.onCreate(data, null); // AlbumSetPage.onCreate(); if (mIsResumed) state.resume(); }
public void onSingleTapUp(int slotIndex) { // slotIndex代表相册的调试,一般0代表第一个相册 if (!mIsActive) return; // 当进入选择模式时 if (mSelectionManager.inSelectionMode()) { MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); if (targetSet == null) return; // Content is dirty, we shall reload soon mSelectionManager.toggle(targetSet.getPath()); mSlotView.invalidate(); } else { // Show pressed-up animation for the single-tap. mAlbumSetView.setPressedIndex(slotIndex); // 手指点击相册的动画 mAlbumSetView.setPressedUp(); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0), FadeTexture.DURATION); // 发送消息 } }
……. mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { @Override public void handleMessage(Message message) { switch (message.what) { case MSG_PICK_ALBUM: { // 这里处理消息,跳转到 pickAlbum方法处理 pickAlbum(message.arg1); break; …….. };
// pickAlbum 的方法 private void pickAlbum(int slotIndex) { if (!mIsActive) return;
MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); // 得到相册集的标识 …. String mediaPath = targetSet.getPath().toString(); // 得到相册的路径path if (mGetAlbum && targetSet.isLeafAlbum()) {….离开albusetPage
} else if (targetSet.getSubMediaSetCount() > 0) { data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath); //add for DRM feature: pass drm inclusio info to next ActivityState if (IS_DRM_SUPPORTED || IS_STEREO_DISPLAY_SUPPORTED) { data.putInt(DrmHelper.DRM_INCLUSION, mMtkInclusion); }// 是否显示相应的drm文件 mActivity.getStateManager().startStateForResult( AlbumSetPage.class, REQUEST_DO_ANIMATION, data); } else { ………. } data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath); mActivity.getStateManager().startStateForResult( AlbumPage.class, REQUEST_DO_ANIMATION, data); // 进入AlbumPage模式(即可以浏览该相册下的图像和视频文件缩略图) } }
|
进入PhotoPage单个相片浏览模式
以上的代码就进去了AlbumPage 浏览缩略图模式。
当单击某个相片的缩略图,就会浏览该相片,处理过程与AlbumSetPage类似。
请看以下代码:
AlbumPage类:
private void onSingleTapUp(int slotIndex) { mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0), FadeTexture.DURATION); // 发送消息 }
mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { @Override public void handleMessage(Message message) { switch (message.what) { case MSG_PICK_PHOTO: { pickPhoto(message.arg1); …… }
pickPhoto 方法;
private void pickPhoto(int slotIndex, boolean startInFilmstrip) { if (!startInFilmstrip) { // 不是幻灯片模式 // Launch photos in lights out mode mActivity.getGLRoot().setLightsOutMode(true); }
MediaItem item = mAlbumDataAdapter.get(slotIndex);// 得到相片的标识 if (item == null) return; // Item not ready yet, ignore the click if (mGetContent) { onGetContent(item); // 通过彩信进来 } else if (mLaunchedFromPhotoPage) { // 通过图片浏览模式进来 …….. onBackPressed(); } else { …………….. if (startInFilmstrip) {// 如果只有相册只有一张照片,直接进入幻灯片 模式 mActivity.getStateManager().switchState(this, PhotoPage.class, data); } else { // 浏览相片模式 mActivity.getStateManager().startStateForResult( PhotoPage.class, REQUEST_PHOTO, data);
|
PhotoView单个相片浏览显示界面
PhotoPage类:
public void onCreate(Bundle data, Bundle restoreState) { …… mPhotoView = new PhotoView(mActivity); // 图片显示的类,opengl mPhotoView.setListener(this); // 设置监听 。。。。。。 mRootPane.addComponent(mPhotoView);// 把显示图片界面添加到画布组件 }
|
到这里,基本的图片浏览过程基本完成了。
Gallery 调用图片浏览整体调用流程图。