Gallery3D源码分析

Ø  Gallery3D概述
    Gallery3D的界面生成和普通的应用程序不一样。普通程序一般一个界面就是一个activity,布局用xml或代码都可以实现,界面切换是activity的切换方式;而Gallery3D没有用androidUI系统,而是用opengl画出来的,即界面是在同一个activity的,如主界面,缩略图界面,单张图片查看界面,标记界面等都属于同一个activity


Ø  主要线程介绍
    在应用程序中有三个非常重要的线程存在:主线程(Galleryactivity的生命周期启动销毁)、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 包含了5ArrayList,其定义如下所示:
public final ArrayList<Layer> updateList = newArrayList<Layer>();  
public final ArrayList<Layer> opaqueList = newArrayList<Layer>();  
public final ArrayList<Layer> blendedList = newArrayList<Layer>();  
public final ArrayList<Layer> hitTestList = newArrayList<Layer>();  
public final ArrayList<Layer> systemList = new ArrayList<Layer>();

RenderView onDrawFrame接口完成每一帧的绘制操作,绘制时遍历 lists 里每个 list 的每一个成员并调用其 renderXXX 函数。主要代码如下所示:
...  
final Lists lists = sLists;  
  
final ArrayList<Layer> updateList = lists.updateList;  
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<Layer> opaqueList = lists.opaqueList;  
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<Layer> blendedList = lists.blendedList;  
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(....)接口,这些接口会在RenderViewonDrawFrame绘制代码中被调用。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,所以所有的事件触发动作都来源于主线程,实际上是主线程中的RenderViewonTouchEvent:
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()请求绘制。于是会重新调用RenderViewonDrawFrame绘制代码,其中有个函数processTouchEvent(),这个函数的主要功能是负责处理事件队列中的事件,查找该事件来源于哪个控件(对应具体的某个Layer子类),然后将事件分发给该控件处理,控件接受到事件的时候会调用自身的onTouchEvent()函数,在这里会根据事件的不同设置一些不同的数据主要是给绘制的时候要用的,最终会调用到真正的事件处理类GestureDetector.Java的相关方法包括对是否是双击阿单击阿等。在这里需要说明一下,它并没有把响应事件的具体实现放在每个layer的子类中,而是提取出了一个类GestureDetector.Java专门负责响应事件。以上就是整个事件的响应流程,事件统一由RenderView负责创建,然后根据条件的不同下发给相应的控件响应。


Ø  切换界面流程
相册界面,缩略图界面,以及图片浏览界面等,这些界面的跳转不同于activity之间的跳转,因为它们并不是每个都对应一个单独的activity而是共享一个activityGallery3D里面用不同的状态来标识不同的界面,这些状态定义在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()最后调用HudLayerupdateViews()方法进行绘制与更新,从而进入相册界面;同样当用户点击相册的时候,会改变状态为STATE_GRID_VIEW,然后重新绘制界面进入缩略图界面,其他界面的切换也是同样的道理,当状态没有发生变化的时候将不会执行回调函数setState()onGridStateChanged()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值