xzw 2019-06-26
图库和相机在内部实现上其实是共用的一个app,即Gallery2。它们是Gallery2的两个不同的入口。图库的主要功能是展示和管理设备中的或者网络上的媒体内容(照片、视频),虽然名字是图库,但是其功能不仅仅限于图片。其代码位于packages/apps/Gallery2。
打开图库应用首先看到的是相册缩略图,点击一个相册后进入这个相册中的照片的缩略图,点击一个照片的缩略图后进入单张照片模式。这些不同的UI之间的切换并没有使用不同的Activity,而是在同一个Actvity中进行的。这个Activity是GalleryActivity(有两个GalleryActivity,这儿指的是com.android.gallery3d.app包中的)。布局文件是main.xml,其主要内容如下:
<RelativeLayout> <include layout=”@layout/gl_root_group”/> <FrameLayout android:id=”@+id/header”/> <FrameLayout android:id=”@+id/footer”/> </RelativeLayout>
接着看gl_root_group.xml,其内容如下:
<merge> <GLRootView /> <View android:id=”@+id/gl_root_cover”/> </merge>
这就是图库UI实现的特殊之处。GLRootView继承自GLSurfaceView。实际上Gallery2基于GLSurfaceView实现了一套UI控件,这套UI组件画在这个GLSurfaceView上。Gallery2的图库功能的UI实现没有采用Android通常的View控件系统。Gallery2实现了GLView、GLRootView、GLCanvas等。GLView就相当于通常Android控件体系中的View,它是所有控件的父类。GLView可以接收触摸事件,并把自己画到GLCanvas上,GLCanvas是一个接口其实现有GLES11Canvas、GLES20Canvas。GLCanvas把自己绘制到GLSurfaceView中。接着说GLView,一个GLView可以有零个或多个子GLView,它们形成一个树结构。渲染和事件处理通过这个数结构传递。GLView必需加入到(Attach)GLRoot中才能完成渲染和接收事件。GLView可以通过调用GLRoot的requestRender()和requestLayoutContentPane()方法实现GLView树的渲染和布局。
GLRootView除了继承自GLSurfaceView之外还实现了GLRoot接口。是所有GLView的根控件。即整个GLView树是添加在它上面的,这通过GLRootView的setContentPane方法实现,有些类似于Activity的setContentView。GLView的渲染在GL线程中进行,事件处理在主线程中进行。这两个线程需要同步。在事件处理和布局的时候GLRootView会获取一个锁,从而避免渲染线程在这个时候执行。这个锁就是GLRootView中的mRenderLock。
总结一下就是Gallery2不同于一般app之处是它的控件从GLView继承而不是View,GLView渲染在GLSurfaceView中。Gallery2实现了自己的一套UI控件系统。
根据UI技术分析一节可以知道图库功能界面的切换本质上时GalleryActivity中GLSurfaceView中GLView的切换。或者可以说GalleryActivity有相册缩略图(AlbumSetPage)、相册照片缩略图(AlbumPage)、单张照片(PhotoPage)、幻灯片(SlideshowPage)四种不同的状态(ActivityState)。实际上AlbumSetPage、AlbumPage、PhotoPage、SlideshowPage都继承自ActivityState,并且它们之间的切换由StateManager来管理。每一个ActivityState都有一个GLView树,这个树的根节点是ActivityState中定义的mContentPane。
对应AlbumSetPage、AlbumPage、PhotoPage、SlideshowPage分别是SlotView、SlotView、PhotoView、SlideshowView。对应的数据适配器分别是AlbumSetDataLoader、AlbumDataLoader、PhotoDataAdapter、SlideshowDataAdapter。用图形表示如下:
数据适配器(Adapter)是数据到UI的桥梁,连接数据源和UI。Gallery2中数据源是MediaSource,MediaSource创建MediaObject实例,GLView渲染的就是一个个的MediaObject。MediaSource由DataManager管理,AlbumSetPage等ActivityState在初始化的时候会通过DataManager获取一个MediaObject,这个MediaObject就是ActivityState的数据的最终来源,即数据适配器的数据来源。界面(AlbumSetPage等ActivityState的子类)没有直接和MediaSource打交道,MediaSource被封装在了DataManager中。
MediaSource的子类有LocalSource、PicasaSource、ComboSource(一个组合源,组合了LocalSource和PicasaSource的功能)、ClusterSource等。MediaObject有两个子类MediaSet和MediaItem。MediaSet是一个集合类,其元素是MediaItem类型。MediaSet又有子类LocalAlbumSet、ClusterAlbumSet、ComboAlbumSet、LocalAlbum、ClusterAlbum、ComboAlbum等。MediaItem又有子类LocalMediaItem、UriImage等。数据模型用图形表示就是: