本文对于runOnGLThread方法的分析主要目的是为了帮助我的课程“拇指接龙游戏”学员更好地理解EasyNDK这个开源框架的使用。借助于这个框架,实现Android JAVA端与Cococ2d-x C++端交互,以及iOS Objective-C端与Cococ2d-x C++端交互将变得异常容易----极大地减少了相关的JNI编程与Objecive-C编程的代码量。但是,在EasyNDK的Android版本示例中在Java主Activity端存在如下代码段:

   
public void ChangeSomethingInCocos()
    {
        this.runOnGLThread(new Runnable()
        {
            @Override
            public void run()
            {
                AndroidNDKHelper.SendMessageWithParameters("ChangeLabelSelector", null);
            }
        });
    }

    上述代码中SendMessageWithParameters方法为什么要运行于runOnGLThread方法中?本文将试图对这部分代码进行充分解释。至于EasyNDK的其他部分的使用就容易理解多了。

一、回顾传统Android编程中使用的runOnUiThread方法

        在android中经常需要用到异步操作,Thread+Handler方式比较繁琐(当然功能也最为强大),而AsyncTask只能执行一次,很多需求不能满足(有关AsyncTask用法,请参考我引用的另外一篇博客)。

      此时,我们可以试试Activity提供的另外一种简单的方法runOnUiThread,runOnUiThread可以帮助你在线程中执行UI更新操作。

        以下为线程中使用runOnUiThread方法的框架代码:

MyActivity.this. runOnUiThread(new Runnable() {   
                    @Override   
                        public void run() {   
  
                           // refresh ui 的操作代码  
  
                        }   
                    });

    这里需要注意:runOnUiThread是Activity中的方法,在我们的工作线程中需要告诉系统是哪个Activity调用,所以前面显式地指明Activity。


    下面为runOnUiThread的宏观代码:


public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
}

   


    从代码可以看到,runOnUiThread首先判断是否是UI线程,不是的话就post,如果是的话就正常运行该线程。只要经过主线程中的Handler.post或者postDelayed处理,线程Runnable都可以被加入到UI主线程的消息循环中,并为主线程的Handler所检索并调用。有关的Handler运行原理,请参考我引用的其他几篇博客文章。


    值得注意的是,本节中的runOnUiThread方法适合于从子线程中更新普通Android View内容时调用。但是,当我们在Android下进行OpenGL ES开发时,也就是本文关注的cocos2d-x开发时,需要使用另一个方法,即下文要讨论的runOnGLThread


二、Cocos2d-x编程中的runOnGLThread方法


    cocos2d-x开发中,一旦涉及到Android平台移植自然要与Cocos2dxActivity这个东西打交道。Cocos2dxActivity是cocos2d-x开发团队的成果,它是一个抽象类,具体形式如下:

public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelperListener {//...}

    我们知道,cocos2d-x是运行于OpenGL平台的。Android平台下进行OpenGL开发要与一个特殊View--GLSurefaceView打交道。GLSurefaceView要使用它自己的渲染器(Render)进行图形渲染,这个Render是运行于一个独立的区别于主GUI线程的子线程上的。


接下来,我们跟踪观察一下接口Cocos2dxHelperListener的定义(它隐藏于文件Cocos2dxHelper.java中):

    public static interface Cocos2dxHelperListener {
        public void showDialog(final String pTitle, final String pMessage);
        public void showEditTextDialog(final String pTitle, final String pMessage, final int pInputMode, final int pInputFlag, final int pReturnType, final int pMaxLength);
        public void runOnGLThread(final Runnable pRunnable);
    }

    其中的前两个方法与Cocos2d-x中显然对话框与文本框有关,在此我们省略有关讨论,而只专注于方法runOnGLThread


    接下来跟踪分析,Cocos2dxActivity中定义上述方法如下: 

@Override
    public void runOnGLThread(final Runnable pRunnable) {
        this.mGLSurfaceView.queueEvent(pRunnable);
    }

    有关Runnable对象,请参考我引用的其他几个博客文章。至于mGLSurfaceView,它是Cocos2dxGLSurfaceView类型的,而Cocos2dxGLSurfaceView是继承自GLSurfaceView的cocos2d-x开发团队的产品。当然,Cocos2dxGLSurfaceView内部也有一个自己的渲染器Cocos2dxRenderer,也是cocos2d-x开发团队在类GLSurfaceView.Renderer基础上稍微扩展的结果。


      颇感遗憾的是,搜索网络上的资源,对于queueEvent方法的解释都不透彻。但是有几篇还是对上面这种表达进行了一定解释(由于本人当前没有时间研讨Android源码,只要先借鉴网络上看法)。说法是:GLSurfaceView的渲染线程与主GUI线程通信有多种方式,其实较为简单的一种便是使用上面的queueEvent方法,把一个Runnable对象投掷到主线程的消息队列中。简言之,通过上面的方法调用,这个Runnable实现的run方法将为主GUI线程对应的Handler所检索出并执行,从而实现了在GLSurfaceView的渲染子线程(Cocos2d-x C++这边)中更新主GUI线程界面内容的目的。至此,文章开始处的代码使用原因便得到解释。

      另外一句话:Cocos2d-x中的runOnGLThread相当于普通Android Java环境下的runOnUiThread方法的功能,起到子线程更新GUI主线程界面之目的。

 

参考文章


1.【COCOS2DX-ANDROID-游戏开发之二二】之 调用Cocos2dxGLSurfaceView (http://blog.csdn.net/teng_ontheway/article/details/17267825)。
2.Android UI thread / main thread(http://blog.csdn.net/teng_ontheway/article/details/17267557)。

3.android中的runOnUiThread(runnable) 
(http://blog.csdn.net/isming/article/details/8622087)。

4.Android开发笔记之:Handler Runnable与Thread的区别详解(http://www.jb51.net/article/37465.htm)。

5.Android的单线程模型(http://www.cnblogs.com/nio-nio/archive/2012/07/23/2604900.html)。

6.Android View.post(Runnable )(http://www.cnblogs.com/akira90/archive/2013/03/06/2946740.html)。 

7.Android GLSurfaceView (http://blog.csdn.net/murongshusheng/article/details/7565771)。

8.android.opengl.GLSurfaceView概述 (http://blog.csdn.net/xqhrs232/article/details/6195824)。