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 {}


并没有继承Activity,而是一个AbstractGalleryActivity,看下这个类
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的相关内容


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        mGLRootView.lockRenderThread();
        try {
            super.onSaveInstanceState(outState);
            getStateManager().saveState(outState);
        } finally {
            mGLRootView.unlockRenderThread();
        }
    }

这个函数的作用是什么?上网自己查,我就不讲了。

    @Override
    protected void onResume() {
        super.onResume();
        mGLRootView.lockRenderThread();
        try {
            getStateManager().resume();
            getDataManager().resume();
        } finally {
            mGLRootView.unlockRenderThread();
        }
        mGLRootView.onResume();
        mOrientationManager.resume();
    }

    @Override
    protected 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 GLSurfaceView
        implements GLSurfaceView.Renderer, GLRoot {}

我们发现GLRootView就是我们以前所说的RenderView,负责控制所有的层和刷新用的。

而GLRoot只是个接口

public interface GLRoot {}

既然GLRootView就是原来的RenderView,那么我们去找渲染刷新的函数,看看消息处理是不是也在里面

   public void onDrawFrame(GL10 gl) {}

发现这个里面并没有消息处理,估计Android工程师觉得将消息处理写在渲染里面纯属乱搞啊,属于恶意搞乱代码结构,我觉得虽然那样是很巧妙,但是也带来了一些问题,比如多点触摸的实现比较麻烦。

android使用了比较正规的办法dispatchTouchEvent来处理触摸事件,然后在mContentView.dispatchTouchEvent各个页面中(注意没有用Layer,而是用的Page或者说View)

    @Override
    public 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 event
            boolean handled = mContentView != null
                    && mContentView.dispatchTouchEvent(event);
            if (action == MotionEvent.ACTION_DOWN && handled) {
                mInDownState = true;
            }
            return handled;
        } finally {
            mRenderLock.unlock();
        }
    }

有个问题,说是分发触摸消息,但是没有循环,只有一个调用啊?


是的,Android采用的办法并不是分层,而是分页面的办法,每个界面都在一个页面里面,每次只要切换页面就可以了,切换页面的时候将mContentView的值设置成制定的页面就可以了。我考虑Android想的是分层将很多控件写在一个层里面,靠隐藏和显示切换,这样有点乱。这个改动是比较好的。


那么这个mContentView的值是什么时候修改的呢?


    @Override
    public 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的实现更为精致一些,这次就说到这里吧。休息,休息一会,下次再说。




你可能感兴趣的:(Gallery3d 学习笔记(13))