Android Gallery3D源码分析
【转】原文地址http://blog.csdn.net/giegie/article/details/6830225
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元素,具体有如下控件。
java代码:
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,其定义如下所示:
java代码:
public final ArrayList<Layer> updateList = new ArrayList<Layer>(); public final ArrayList<Layer> opaqueList = new ArrayList<Layer>(); public final ArrayList<Layer> blendedList = new ArrayList<Layer>(); public final ArrayList<Layer> hitTestList = new ArrayList<Layer>(); public final ArrayList<Layer> systemList = new ArrayList<Layer>();
RenderView 的onDrawFrame接口完成每一帧的绘制操作,绘制时遍历 lists 里每个 list 的每一个成员并调用其 renderXXX 函数。主要代码如下所示:
java代码:
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 如下所示:
Layer提供了update(....),renderOpaque(....),renderBlended(....)接口,这些接口会在RenderView的onDrawFrame绘制代码中被调用。GridLayer 中有个 GridDrawManager,专门负责绘制,在前面的那几个接口中会调用到GridDrawManager的一些具体绘制函数实现真正的画图工作如:
java代码:
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:
java代码:
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里面如下:
java代码:
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()。
转载于:https://www.cnblogs.com/zhouyuchao/archive/2012/08/20/2647872.html
Android Gallery3D源码分析相关推荐
- android 3d城市源码,[转载]android Gallery3D源码分析
一.布局 gallery3d的界面生成和普通的应用程序不一样.普通程序一般一个界面就是一个activity,布局用xml或代码都可以实现,界面切换是activity的切换方式:而gallery3d没有 ...
- Android HandlerThread 源码分析
HandlerThread 简介: 我们知道Thread线程是一次性消费品,当Thread线程执行完一个耗时的任务之后,线程就会被自动销毁了.如果此时我们又有一 个耗时任务需要执行,我们不得不重新创建 ...
- Android ADB 源码分析(三)
前言 之前分析的两篇文章 Android Adb 源码分析(一) 嵌入式Linux:Android root破解原理(二) 写完之后,都没有写到相关的实现代码,这篇文章写下ADB的通信流程的一些细节 ...
- 【Android SDM660源码分析】- 02 - UEFI XBL QcomChargerApp充电流程代码分析
[Android SDM660源码分析]- 02 - UEFI XBL QcomChargerApp充电流程代码分析 一.加载 UEFI 默认应用程序 1.1 LaunchDefaultBDSApps ...
- 【Android SDM660源码分析】- 03 - UEFI XBL GraphicsOutput BMP图片显示流程
[Android SDM660源码分析]- 03 - UEFI XBL GraphicsOutput BMP图片显示流程 1. GraphicsOutput.h 2. 显示驱动初化 DisplayDx ...
- 【Android SDM660源码分析】- 01 - 如何创建 UEFI XBL Protocol DXE_DRIVER 驱动及UEFI_APPLICATION 应用程序
[Android SDM660源码分析]- 01 - 如何创建 UEFI XBL Protocol DXE_DRIVER 驱动及UEFI_APPLICATION 应用程序 一.创建DXE_DRIVER ...
- 【Android SDM660源码分析】- 04 - UEFI ABL LinuxLoader 代码分析
[Android SDM660源码分析]- 04 - UEFI ABL LinuxLoader 代码分析 1. LinuxLoader.c 系列文章: <[Android SDM660开机流程] ...
- Android 音频源码分析——AndroidRecord录音(一)
Android 音频源码分析--AndroidRecord录音(一) Android 音频源码分析--AndroidRecord录音(二) Android 音频源码分析--AndroidRecord音 ...
- Android框架源码分析——从设计模式角度看 Retrofit 核心源码
Android框架源码分析--从设计模式角度看 Retrofit 核心源码 Retrofit中用到了许多常见的设计模式:代理模式.外观模式.构建者模式等.我们将从这三种设计模式入手,分析 Retrof ...
最新文章
- 20W奖金+实习机会:阿里巴巴达摩院最新时间序列赛事来了!
- antd Form.Item 中如何获取到Select的label值
- tableview下拉刷新
- float相乘后的类型_Psychopy | 第1期:数据类型及运算符
- mysql 查看集群状态_MySQL数据库集群正确配置步骤
- mysql存储过程执行update_MySQL存储过程实现动态执行SQL
- 香港中文大学(深圳)吴保元教授课题组博士后招聘
- linux远程执行命令
- python 2 函数
- UDK2017下载及编译
- 《大型网站技术架构:核心原理与案例分析》读书笔记-高可用
- MATLAB数字图像处理(一)图像的基本操作
- reader java_Java Reader 类
- 云计算、计算虚拟化、网络基础简介
- 两步解决:PDF旋转后怎么保存?
- 【Unity】基础知识结构总结
- 2022年打工人转行实录!你后悔转行了吗?
- 【Linux】Linux input子系统之Input event codes
- 多台电脑共享键盘鼠标
- 最新美团面试集合(一面+二面+三面+重点技术面试题)附面试解析
热门文章
- bootstrap拖动div_JS组件系列——Bootstrap Table 表格行拖拽(二:多行拖拽)
- oracle有没有mysql if_Oracle中没有 if exists(...)
- 正弦定理和余弦定理_高三 | 数学必修五正弦定理和余弦定理应用举例考点梳理...
- java 后台线程作用_Java 后台线程介绍
- html 生成唯一码,生成唯一32位ID编码代码,以满足对ID编号的唯一性加资源性解决问题...
- 查看nginx进程_nginx的进程模型与配置
- 充值后的充值金额提交到账户金额中
- java怎样获取线程的进度_java中的多线程——进度2
- python执行系统命令的方法_python执行系统命令的方法 :os.system(),subprocess.popen(),command...
- 命运歌姬服务器停服维护中,命运歌姬3月4日更新什么?命运歌姬3月4日更新维护公告[多图]...