分类: Java
2011-12-08 12:00:07
Ø
Gallery3D概述
Gallery3D的界面生成和普通的应用程序不一样。普通程序一般一个界面就是一个
activity,布局用
xml或代码都可以实现,界面切换是
activity的切换方式;而
Gallery3D没有用
android的
UI系统,而是用
opengl画出来的
,即界面是在同一个
activity的,如主界面,缩略图界面,单张图片查看界面,标记界面等都属于同一个
activity。
Ø
主要线程介绍
在应用程序中有三个非常重要的线程存在:主线程(
Gallery随
activity的生命周期启动销毁)、
MediaFeed初始化线程(进入程序时只运行一次,用于加
载相册初始信息)、
MediaFeed监听线程(一直在跑,监听相册和相片的变更),其中
MediaFeed初始化线程的工作是:调用
MediaFeed 的
loadMediaSets加载相册,
MediaFeed监听线程
MediaFeed.run()的工作是:根据
“内容变化监听器
“返回的媒体变动消息
(增删改),持续不断的更新
MediaFeed中的相册和相片变量。
Ø
控件
Gallery3D中定义了很多控件它们都继承自
com.cooliris.media.Layer,分别代表不同场景和界面下的
UI元素,具体有如下控件
com.cooliris.media.GridLayer :网格所略图显示和单个图片显示
com.cooliris.media.BackgroundLayer :背景
com.cooliris.media.HudLayer :相册显示
com.cooliris.media.ImageButton :图片按钮(主要指进入
Gallery后右上角的那个控件)
com.cooliris.media.TimeBar :进入
Gallery后下方可拖动的悬浮控件
com.cooliris.media.MenuBar :点击图片时弹出的菜单按钮
com.cooliris.media.PopupMenu :点击菜单按钮后弹出来的菜单项
com.cooliris.media.PathBarLayer :如今
Gallery后左上方显示图片路径的空间
Ø
渲染流程
Gallery3D的渲染从
RenderView 开始。
RenderView 从
GLSurfaceView 继承而来,采用了通知型绘制模式,即通过调用
requestRender 通知
RenderView 重绘屏幕。
RenderView 将所有需要绘制的对象都保存一个
Lists中,
Lists 包含了
5个
ArrayList,其定义如下所示:
public final ArrayList
public final ArrayList
public final ArrayList
public final ArrayList
public final ArrayList
RenderView 的
onDrawFrame接口完成每一帧的绘制操作,绘制时遍历
lists 里每个
list 的每一个成员并调用其
renderXXX 函数。主要代码如下所示:
...
final Lists lists = sLists;
final ArrayList
boolean isDirty = false;
for (int i = 0, size = updateList.size(); i != size; ++i) {
boolean retVal = updateList.get(i).update(this,mFrameInterval);
isDirty |= retVal;
}
if (isDirty) {
requestRender();
}
// Clear the depth buffer.
gl.glClear(GL11.GL_DEPTH_BUFFER_BIT);
gl.glEnable(GL11.GL_SCISSOR_TEST);
gl.glScissor(0, 0, getWidth(), getHeight());
// Run the opaque pass.
gl.glDisable(GL11.GL_BLEND);
final ArrayList
for (int i = opaqueList.size() - 1; i >= 0; --i) {
final Layer layer = opaqueList.get(i);
if (!layer.mHidden) {
layer.renderOpaque(this,gl);
}
}
// Run the blended pass.
gl.glEnable(GL11.GL_BLEND);
final ArrayList
for (int i = 0, size = blendedList.size(); i != size; ++i) {
final Layer layer = blendedList.get(i);
if (!layer.mHidden) {
layer.renderBlended(this,gl);
}
}
gl.glDisable(GL11.GL_BLEND);
lists 的各个
list 里包含的各个
layer 如下所示:
lists
|-----------------------|-----------------------|-----------------------|-----------------------|
updateList opaqueList
blendedList
systemList hitTestList
|
| | |
|
GridLayer GridLayer GridLayer GridLayer GridLayer
BackgroudLayer BackgroudLayer BackgroudLayer
HudLayer HudLayer HudLayer
HudLayer
TimeBar TimeBar
TimeBar
PathBar
PathBar
PathBar
XXXButton
XXXButton XXXButton
XXXMenu XXXMenu XXXMenu
Layer提供了
update(....),
renderOpaque(....),
renderBlended(....)接口,这些接口会在
RenderView的
onDrawFrame绘制代码中被调用。
GridLayer 中有个
GridDrawManager,专门负责绘制,在前面的那几个接口中会调用到
GridDrawManager的一些具体绘制函数实现真正的画图工作如:
drawDisplayItem(view, gl, displayItem, texture, PASS_THUMBNAIL_CONTENT,placeholder, displayItem.mAnimatedPlaceholderFade); 画缩略图的
drawDisplayItem(view, gl, displayItem, texture, PASS_FOCUS_CONTENT, null,0.0f);画单张图片的
drawDisplayItem(view, gl, itemDrawn, textureToUse, PASS_FRAME, previousTexture,ratio);画边框的
drawDisplayItem(view, gl, displayItem, textureString, PASS_TEXT_LABEL, null,0);画文本标签的
drawDisplayItem(view, gl, displayItem, textureToUse, PASS_SELECTION_LABEL,null, 0);画选中标记的
drawDisplayItem(view, gl, displayItem, videoTexture, PASS_VIDEO_LABEL, null,0);画视频标记的
drawDisplayItem(view, gl, displayItem, locationTexture, PASS_LOCATION_LABEL,null, 0);画位置标记的
drawDisplayItem(view, gl, displayItem, locationTexture, PASS_MEDIASET_SOURCE_LABEL,transparentTexture,0.85f);画源来源图标的
(相机或一般文件夹
)
Ø
事件机制
由于所有界面都同属于一个
activity,所以所有的事件触发动作都来源于主线程,实际上是主线程中的
RenderView的
onTouchEvent:
public boolean onTouchEvent(MotionEvent event) {
// Ignore events received before thesurface is created to avoid
// deadlocking with GLSurfaceView'sneedToWait().
if (mGL == null) {
returnfalse;
}
// Wait for the render thread toprocess this event.
if (mTouchEventQueue.size() > 8&& event.getAction() == MotionEvent.ACTION_MOVE)
return true;
synchronized (mTouchEventQueue) {
MotionEventeventCopy = MotionEvent.obtain(event);
mTouchEventQueue.addLast(eventCopy);
requestRender();
}
return true;
}
在这里它将所有的触屏事件放在一个待处理的事件队列里面,当队列里面的事件数大于
8或者该事件属于拖动事件的时候它将等待,否则会将该事件加入队列,并调用
requestRender()请求绘制。于是会重新调用
RenderView的
onDrawFrame绘制代码,其中有个函数
processTouchEvent(),这个函数的主要功能是负责处理事件队列中的事件,查找该事件来源于哪个控件
(对应具体的某个
Layer子类
),然后将事件分发给该控件处理,控件接受到事件的时候会调用自身的
onTouchEvent()函数,在这里会根据事件的不同设置一些不同的数据主要是给绘制的时候要用的,最终会调用到真正的事件处理类
GestureDetector.Java的相关方法包括对是否是双击阿单击阿等。在这里需要说明一下,它并没有把响应事件的具体实现放在每个
layer的子类中,而是提取出了一个类
GestureDetector.Java专门负责响应事件。以上就是整个事件的响应流程,事件统一由
RenderView负责创建,然后根据条件的不同下发给相应的控件响应。
Ø
切换界面流程
相册界面,缩略图界面,以及图片浏览界面等,这些界面的跳转不同于
activity之间的跳转,因为它们并不是每个都对应一个单独的
activity而是共享一个
activity。
Gallery3D里面用不同的状态来标识不同的界面,这些状态定义在
GridLayer里面如下:
public static final int STATE_MEDIA_SETS = 0;
public static final int STATE_GRID_VIEW = 1;
public static final int STATE_FULL_SCREEN = 2;
public static final int STATE_TIMELINE = 3;
状态的变化引起界面的变化,
Gallery3D里面采用了通知模式,状态变化的接口为
GridLayer中的
public void setState(int state),通知接口为
HudLayer中的
public void onGridStateChanged()。界面的切换是由事件发起的,因此在事件的响应函数里面会对用户的触屏动作分解成一个个的状态,如刚进入
Gallery3D的时候会通过调用
setState(STATE_MEDIA_SETS)设置状态为
STATE_MEDIA_SETS,并发送通知即调用
onGridStateChanged()最后调用
HudLayer的
updateViews()方法进行绘制与更新,从而进入相册界面;同样当用户点击相册的时候,会改变状态为
STATE_GRID_VIEW,然后重新绘制界面进入缩略图界面,其他界面的切换也是同样的道理,当状态没有发生变化的时候将不会执行回调函数
setState()和
onGridStateChanged()。