Gallery3d 学习笔记(13)
Gallery3d 学习笔记(13)
上次我们探讨了Android 4.0中Gallery3d中的视频播放器,现在剩下的代码非常的多,我们先整体看下有那些包
com.android.gallery3d.anim;//动画
com.android.gallery3d.app;//应用
com.android.gallery3d.common;//通用
com.android.gallery3d.data;//数据源
com.android.gallery3d.gadget;//小部件
com.android.gallery3d.onetimeinitializer;//小部件
com.android.gallery3d.photoeditor;//编辑图片
com.android.gallery3d.photoeditor.actions;//编辑图片
com.android.gallery3d.photoeditor.filters;//
com.android.gallery3d.picasasource;//毕加索
com.android.gallery3d.provider;//provider
com.android.gallery3d.settings;//设置
com.android.gallery3d.ui;//UI
com.android.gallery3d.util;//通用
光是包就不少,十几个,不过Android做了分类,这点是很好的改进,毕竟类增加了非常多,不分类就更难看了。
我们还是先从app包中的Gallery.java看起吧
public final class Gallery extends AbstractGalleryActivity implements OnCancelListener {}
public class AbstractGalleryActivity extends Activity implements GalleryActivity {}
看起来只是增加对Activity加了个接口的实现,我们看下这个接口要实现什么
public interface GalleryActivity extends GalleryContext {public StateManager getStateManager();public GLRoot getGLRoot();public GalleryActionBar getGalleryActionBar();public OrientationManager getOrientationManager();public TransitionStore getTransitionStore();
}
第一个是状态管理器,还记得2.3中使用不同的状态切换界面么,4.0也采取了类似的办法,
第二个getGLRoot(),看起来Android还是要用OpenGL来画啊?
第三个是GalleryActionBar,ActionBar是2.3上面没有的东西,一个通用的控件而已,一个条型的控件
第四个是定向管理器,
第五个是过渡存储包,这两个比较难理解,后面再看代码理解吧。
我发现4.0的Gallery原理和2.3里面的非常的像,2.3的理解好了之后,对于4.0的非常有帮助,而且4.0代码非常的庞大,没有基础会容易晕。
我们先按照2.3使用OpenGL的原理来看下,4.0 的Gallery3上的区别。
再AbstractGalleryActivity中我们先看OpenGL的相关内容
@Overrideprotected void onSaveInstanceState(Bundle outState) {mGLRootView.lockRenderThread();try {super.onSaveInstanceState(outState);getStateManager().saveState(outState);} finally {mGLRootView.unlockRenderThread();}}
这个函数的作用是什么?上网自己查,我就不讲了。
@Overrideprotected void onResume() {super.onResume();mGLRootView.lockRenderThread();try {getStateManager().resume();getDataManager().resume();} finally {mGLRootView.unlockRenderThread();}mGLRootView.onResume();mOrientationManager.resume();}
@Overrideprotected void onPause() {super.onPause();mOrientationManager.pause();mGLRootView.onPause();mGLRootView.lockRenderThread();try {getStateManager().pause();getDataManager().pause();} finally {mGLRootView.unlockRenderThread();}MediaItem.getMicroThumbPool().clear();MediaItem.getThumbPool().clear();MediaItem.getBytesBufferPool().clear();}
发现都指向了一个叫做mGLRootView的成员变量,保持和这个同步动作。
import com.android.gallery3d.ui.GLRoot;
import com.android.gallery3d.ui.GLRootView;
发现还导入了一个类,GLRoot,而且在
public GLRoot getGLRoot() {return mGLRootView;}
注意mGLRootView是GLRootView的实例,为什么要返回一个GLRoot的类型呢?
我们看下这两个类都是什么关系
public class GLRootView extends GLSurfaceViewimplements GLSurfaceView.Renderer, GLRoot {}
我们发现GLRootView就是我们以前所说的RenderView,负责控制所有的层和刷新用的。
而GLRoot只是个接口
public interface GLRoot {}
既然GLRootView就是原来的RenderView,那么我们去找渲染刷新的函数,看看消息处理是不是也在里面
public void onDrawFrame(GL10 gl) {}
发现这个里面并没有消息处理,估计Android工程师觉得将消息处理写在渲染里面纯属乱搞啊,属于恶意搞乱代码结构,我觉得虽然那样是很巧妙,但是也带来了一些问题,比如多点触摸的实现比较麻烦。
android使用了比较正规的办法dispatchTouchEvent来处理触摸事件,然后在mContentView.dispatchTouchEvent各个页面中(注意没有用Layer,而是用的Page或者说View)
@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {if (!isEnabled()) return false;int action = event.getAction();if (action == MotionEvent.ACTION_CANCEL|| action == MotionEvent.ACTION_UP) {mInDownState = false;} else if (!mInDownState && action != MotionEvent.ACTION_DOWN) {return false;}if (mCompensation != 0) {event.transform(mCompensationMatrix);}mRenderLock.lock();try {// If this has been detached from root, we don't need to handle eventboolean handled = mContentView != null&& mContentView.dispatchTouchEvent(event);if (action == MotionEvent.ACTION_DOWN && handled) {mInDownState = true;}return handled;} finally {mRenderLock.unlock();}}
有个问题,说是分发触摸消息,但是没有循环,只有一个调用啊?
是的,Android采用的办法并不是分层,而是分页面的办法,每个界面都在一个页面里面,每次只要切换页面就可以了,切换页面的时候将mContentView的值设置成制定的页面就可以了。我考虑Android想的是分层将很多控件写在一个层里面,靠隐藏和显示切换,这样有点乱。这个改动是比较好的。
那么这个mContentView的值是什么时候修改的呢?
@Overridepublic void setContentPane(GLView content) {if (mContentView == content) return;if (mContentView != null) {if (mInDownState) {long now = SystemClock.uptimeMillis();MotionEvent cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);mContentView.dispatchTouchEvent(cancelEvent);cancelEvent.recycle();mInDownState = false;}mContentView.detachFromRoot();BasicTexture.yieldAllTextures();}mContentView = content;if (content != null) {content.attachToRoot(this);requestLayoutContentPane();}}
那么SetContentPane这个函数又是谁调用的呢?
在页面的OnResume的时候
public void onResume() {super.onResume();mIsActive = true;setContentPane(mRootPane);
而Page里面没有实现这个方法,是继承于ActivityState,你会发现Page都是继承于他的,那他又是如何实现的呢?
protected void setContentPane(GLView content) {mActivity.getGLRoot().setContentPane(content);}
转了几个弯,才调用到我们的setContentPane,实现了Page和GlrootView的关联,并实现了触摸消息的分发。
看起来,Android的实现更为精致一些,这次就说到这里吧。休息,休息一会,下次再说。