android 3d城市源码,[转载]android Gallery3D源码分析

唐弘和
2023-12-01

一、布局

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

Ø重要线程推荐

在利用过程中有三个极其重要的线程存在:主线程(Gallery随activity的生命周期启用烧毁)、MediaFeed初始化线程(进去过程时只运行顺次,用于加载相册初始消息)、MediaFeed监听线程(始终在跑,监听相册和相片的改变),其中MediaFeed初始化线程的工作是:调用MediaFeed

的loadMediaSets加载相册,MediaFeed监听线程MediaFeed.run()的工作是:依据“内容改变监听器“归来的媒体改变消息(增删改),继续不时的更新

MediaFeed中的相册和相片变量。

那么这界面布局不同的界面是如何组合到一起的呢?分析代码,可以把它看成一个状态机

1、标记模式 public static final int MODE_SELECT =

1;(HudLayer)

包含了主界面标记模式,缩略界面矩阵游览时标记模式、缩略图界面分类游览时标记模式3个界面

2、普通模式 public static final int

MODE_NORMAL = 0;(HudLayer)

包含了 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;缩略图界面分类浏览

Ø切换界面流程

相册界面,缩略图界面,以及图片博览界面等,这些界面的跳转不同于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()。

有了以上状态分类后,在渲染的时候就能根据些界面的组成来定哪些控件譔隐藏,哪些要显示了。

下面是基本控件:

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后左上方揭示图片路径的空间

在渲染时,每一帧所有界面上的元素都画了,由于根据上面的状态只把特定窗口的特定元素显示出来,其它窗口中的隐藏,所以不会乱。

Layer是上面控件的基类,上面控件的类也就有了下面两个方法来隐藏不譔显示的界面元素。

public boolean isHidden()

{

return

mHidden;

}

public void setHidden(boolean

hidden) {

if (mHidden

!= hidden) {

mHidden =

hidden;

onHiddenChanged();

}

}

下面是根据上面分类来画不同元素所用的标识:

public static final int

PASS_THUMBNAIL_CONTENT = 0;

public static final int

PASS_FOCUS_CONTENT = 1;

public static final int

PASS_FRAME = 2;

public static final int

PASS_PLACEHOLDER = 3;

public static final int

PASS_FRAME_PLACEHOLDER = 4;

public static final int

PASS_TEXT_LABEL = 5;

public static final int

PASS_SELECTION_LABEL = 6;

public static final int

PASS_VIDEO_LABEL = 7;

public static final int

PASS_LOCATION_LABEL = 8;

public static final int

PASS_MEDIASET_SOURCE_LABEL = 9;

drawDisplayItem(view, gl, displayItem, texture,

PASS_THUMBNAIL_CONTENT, placeholder,

displayItem.mAnimatedPlaceholderFade);

画缩略图的,注掉此句,前两屏只显示框,第三屏OK

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);画源来源图标的(相机或一般文件夹)

Ø渲染流程

Gallery3D的渲染从 RenderView 开始。RenderView 从 GLSu***ceView

继承而来,批准了通知型描摹形式,即穿越调用requestRender 通知 RenderView 重绘屏幕。RenderView

将所有必需描摹的对象都保留一个 Lists中,Lists 包括了5个ArrayList,其定义如下所示:

public final ArrayList

updateList =

newArrayList();

public final ArrayList

opaqueList =

newArrayList();

public final ArrayList

blendedList =

newArrayList();

public final ArrayList

hitTestList =

newArrayList();

public final ArrayList

systemList = new

ArrayList();

RenderView 的onDrawFrame接口告终每一帧的描摹垄断,描摹时遍历 lists 里每个 list 的每一个成员并调用其

renderXXX 函数。重要代码如下所示:

...

final Lists lists = sLists;

final ArrayList updateList =

lists.updateList;

boolean isDirty = false;

for (int i = 0,imomc.com 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 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 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

|-----------------------|-----------------------|-----------------------|-----------------------|

updateListopaqueList blendedList systemListhitTestList

| ||| |

GridLayerGridLayer GridLayerGridLayerGridLayer

BackgroudLayerBackgroudLayer BackgroudLayer

HudLayerHudLayerHudLayerHudLayer

TimeBarTimeBar TimeBar

PathBar PathBar PathBar

XXXButton XXXButtonXXXButton

XXXMenuXXXMenuXXXMenu

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 thesu***ce is created to

avoid

// deadlocking with GLSu***ceView'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负责创立,然后依据条件的不同下发给相应的控件响应

二、特效

举如何显示一张图片为例,在图片完全显示出来经过这样一个过程,附近的图片渐小渐出,当前图片渐大渐入,当前图片逐渐变大直到全屏。实现这个特效,要进行很多帧的渲染。就是说并不是只调一次onDrawFrame函数就可以了,要调用多次。可以把这个特效的实现想成一个状态变化的过程,在每一个状态,纹理的显示大小和位置都不同,这也符合动画的基本原理。放大、缩小我们只要改变顶点数据就可以做到,gallery3d也是这样做的,下面是主要代码:

我们知道调用onDrawFrame来渲染,最后调到下面的drawFocusItems函数,

GridQuad quad = GridDrawables.sFullscreenGrid[vboIndex];

float u = texture.getNormalizedWidth();

float v = texture.getNormalizedHeight();

float imageWidth = texture.getWidth();

float imageHeight = texture.getHeight();

boolean portrait = ((theta / 90) % 2 == 1);

if (portrait) {

viewAspect =

1.0f / viewAspect;

}

quad.resizeQuad(viewAspect, u, v, imageWidth,

imageHeight);//改变用来贴图片的长方形的大小

quad.bindArrays(gl);//绑定新数据,为渲染做准备。

而位置的改变有两种方式,一种是直接以顶点数据中改变,另一种是计算出在3维3个方向的偏移量,再调用gltranslate来做,从代码可以看出采用的是第二种方式来做的,比第一种方式更方便一些。代码:

gl.glTranslatef(-translateXf, -translateYf, -translateZf);

而这里的3个偏移量的计算是和camera相关的,相关文件为GridCamera.java,GridCameraManager.java,过程很复杂,理清楚后再细化吧。

cache管理

下面是cache文件

/sdcard/Android/data/com.cooliris.media/cache/local-album-cache

d---rwxr-x system sdcard_rw 2010-05-21

09:56 local-album-cache

d---rwxr-x system sdcard_rw 2010-05-21

09:56 local-meta-cache

----rwxr-x system sdcard_rw 299877 2010-05-28 07:36

local-album-cachechunk_0

d---rwxr-x system sdcard_rw 2010-05-21

09:56 geocoder-cache

----rwxr-x system sdcard_rw 284

2010-05-28 07:36 local-album-cacheindex

d---rwxr-x system sdcard_rw 2010-05-21

09:56 local-image-thumbs

d---rwxr-x system sdcard_rw 2010-05-21

09:56 local-video-thumbs

d---rwxr-x system sdcard_rw 2010-05-21

09:56 picasa-thumbs

----rwxr-x system sdcard_rw 80

2010-05-28 07:36 local-meta-cachechunk_0

----rwxr-x system sdcard_rw 164

2010-05-28 07:36 local-meta-cacheindex

d---rwxr-x system sdcard_rw 2010-05-21

09:56 hires-image-cache

----rwxr-x system sdcard_rw 627629 2010-05-28 07:37

local-image-thumbschunk_0

----rwxr-x system sdcard_rw 3914

2010-05-21 09:56 local-image-thumbsindex

----rwxr-x system sdcard_rw 53343 2010-05-28 07:34

hires-image-cache-4982941342287215583_1024.cache

----rwxr-x system sdcard_rw 237692 2010-05-28 07:33

hires-image-cache3684568484369117627_1024.cache

----rwxr-x system sdcard_rw 133182 2010-05-28 07:34

hires-image-cache607542544081226432_1024.cache

----rwxr-x system sdcard_rw 83223 2010-05-28 07:34

hires-image-cache4275479623210216146_1024.cache

----rwxr-x system sdcard_rw 292837 2010-05-28 07:34

hires-image-cache-646316556936433937_1024.cache

----rwxr-x system sdcard_rw 191377 2010-05-28 07:35

hires-image-cache2631364604509958174_1024.cache

----rwxr-x system sdcard_rw 366905 2010-05-28 07:35

hires-image-cache-3280562009766080884_1024.cache

----rwxr-x system sdcard_rw 323671 2010-05-28 07:35

hires-image-cache5752471827533329222_1024.cache

创建cache的关键代码

LocalDataSource

public static final DiskCache sThumbnailCache = new

DiskCache("local-image-thumbs");----------------------local-image-thumbs

local-image-thumbschunk_0 local-image-thumbsindex

public static final DiskCache sThumbnailCacheVideo = new

DiskCache("local-video-thumbs");--------------------local-video-thumbs

public static final DiskCache sAlbumCache = new

DiskCache("local-album-cache");----------------------local-album-cache local-album-cacheindex

public static final DiskCache sMetaAlbumCache = new

DiskCache("local-meta-cache");------------------local-meta-cache local-meta-cacheindex

getChunkFile

--------------local-meta-cachechunk_0 local-album-cachechunk_0

ReverseGeocoder:: private static

final DiskCache sGeoCache = new DiskCache("geocoder-cache");

-------------------------geocoder-cache

PicasaDataSource:: public static final DiskCache sThumbnailCache =

new

DiskCache("picasa-thumbs");-----------------------------picasa-thumbs

UriTexture::writeToCache --------------------------hires-image-cache-xxx_1024.cache

欢迎大家多交流,不对之处请大家指正。

 类似资料: