分析template project之proj.android(2)

2015年03月22日 11:53 0 点赞 0 评论 更新于 2017-05-09 09:31

1、深入阅读org.cocos2dx.cpp.AppActivity

主Activity “AppActivity” 继承自 Cocos2dxActivityCocos2dxActivity 是一个继承自 Activity 并实现了 Cocos2dxHelperListener 接口的抽象类。

抽象类相关知识

抽象类是不允许实例化的类,使用关键字 abstract 修饰。如果一个类中含有 abstract 方法,那么这个类必须使用 abstract 修饰;反之,abstract 类中可以没有 abstract 方法。抽象类不能有抽象构造函数或抽象静态方法。Abstract 类的子类需要为其父类中的所有抽象方法提供实现,否则它们也是抽象类。虽然不能创建 abstract 类的实例,但可以创建一个类型为抽象类的变量,并让它指向具体子类的一个实例。

Cocos2dxHelperListener 接口

Cocos2dxHelperListener 接口是一个 public static interface,定义了三个 public 函数:showDialogshowEditTextDialogrunOnGLThread。接口必须由具体类实现才有意义,所以是 public;接口中的数据对所有实现类只有一份,所以是 static,即单例。

Cocos2dxActivity 类的变量定义

1.1.1、private final static String TAG = Cocos2dxActivity.class.getSimpleName();

该变量用于打 log 时起到标示作用。getSimpleName() 方法返回源代码中给出的底层类的简称。

1.1.2、private Cocos2dxGLSurfaceView mGLSurfaceView;

Cocos2dxGLSurfaceView 继承自 GLSurfaceViewGLSurfaceView 是 OpenGL 绘制所在的容器。为了在 Android 应用中使用 OpenGLES 绘画,必须创建一个 view 作为容器,最直接的方式是从 GLSurfaceView 派生一个类。使用 GLSurfaceView 几乎是整合 OpenGLES 到应用的唯一方式,对于全屏或近全屏的 graphicsview 是最好的选择。如果只是在某个小部分显示 OpenGLES 图形,可以考虑 TextureView,也可以使用 SurfaceView 创建一个 OpenGLES viewGLSurfaceView 中实际的绘制任务在 GLSurfaceView.Renderer 中,所以其代码较少,但通常需要扩展这个类来响应触摸事件。

Cocos2dxGLSurfaceView 类的变量定义

1.2.1、private static Handler sHandler;

Handler 在 Android 中主要负责发送和处理消息,其主要用途有两个:一是按计划发送消息或执行某个 Runnable;二是将从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新 UI 线程)。

1.2.2、private static Cocos2dxGLSurfaceView mCocos2dxGLSurfaceView;

1.2.3、private static Cocos2dxTextInputWraper sCocos2dxTextInputWraper;

Cocos2dxTextInputWraper 是实现了 TextWatcher 接口和 OnEditorActionListener 接口的类。

Cocos2dxTextInputWraper 类的变量和函数
  • 变量private final Cocos2dxGLSurfaceView mCocos2dxGLSurfaceView;
  • 函数:构造函数 public Cocos2dxTextInputWraper(final Cocos2dxGLSurfaceView pCocos2dxGLSurfaceView),将输入参数定义赋值给内部变量。

1.2.4、private Cocos2dxRenderer mCocos2dxRenderer;

Cocos2dxRenderer 是实现了 GLSurfaceView.Renderer 接口的类,实际的绘图动作都在 GLSurfaceView.Renderer 里面发生。

Cocos2dxRenderer 类的函数
  • public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig)
  • 作用:通过 JNI 调用 native 层的 Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit 函数。进行一系列的初始化操作,包括获取(或者创建)单例 s_SharedDirectorDirector 的子类,Ref 的孙子类)、单例 Configuration 对象(Ref 的子类),实例化多个对象和变量,如 scenceNodeSchedulerActionManagerEventDispatcher 等,并进行相关的初始化设置。创建一个新的 glviewGLViewImplGLView 的子类,Ref 的孙子类)的实例,并进行一系列的配置。最后开始运行(调用真正的 Cocos2d-x 开发者的入口函数 AppDelegate::applicationDidFinishLaunching()),进行一些场景和层的创建、添加操作,以及设置动画延迟等。
  • 详细初始化过程
  • 调用 Director 类的 getInstance 函数,创建(或者获取)s_SharedDirector 单例,初始化相关变量,然后调用其父类 Directorinit 函数。
  • 实例化多个对象,如 SceneCameraEventCustom 等,并进行相关的初始化设置。
  • 初始化多个变量,如 accumDt_frameRate 等。
  • 实例化 SchedulerActionManager 等,并进行关联。
  • 实例化 TextureCacheRendererConsole 等对象。
  • 创建 GLViewImpl 实例,并进行初始化和配置。
  • 设置 directorglview,开始运行应用。
  • public void onSurfaceChanged(final GL10 pGL10, final int pWidth, final int pHeight)
  • 该方法在 surface 大小改变时被调用,是设置 OpenGL 视图端的好地方。如果相机是固定的,不会围着场景移动,也可以在这里设置相机。
  • public void onDrawFrame(final GL10 gl)
  • 作用:在这个函数中加入了延迟动画时间的限制,在限制之内会直接通过 JNI 层调用 native 层的 Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender。然后调用 drawScene 函数,根据延迟时间判断是否需要跳过一帧,若没有暂停,更新 _scheduler_eventDispatcher,进行清屏、设置矩阵、绘制、交换缓冲区等操作。
  • 每帧的时候该方法都会被调用,用于绘制场景是可靠的。可以通过调用 glClear 方法清除帧缓存,接着通过其他的 OpenGL ES 调用绘制当前的场景。
  • public void handleOnResume()
  • public void handleOnPause()

1.2.5、private Cocos2dxEditText mCocos2dxEditText;

Cocos2dxEditText 是继承自 EditText 的类。

Cocos2dxGLSurfaceView 类的函数

1.2.6、构造函数

调用父类构造函数,并调用 initView 函数。

1.2.7、protected void initView()

设置 GL 版本、SurfaceView 等变量以及消息处理方法。

  • setEGLContextClientVersion(2):当使用 OpenGLES 2.0 时,必须在 GLSurfaceView 构造器中调用该函数,说明将要使用 2.0 版的 API。
  • setFocusableInTouchMode(true):确保能接收到触屏事件。

1.2.8、public void onResume()

调用父类的 onResume,设置渲染模式,使用线程通信控制渲染线程恢复。

  • setRenderMode(RENDERMODE_CONTINUOUSLY):渲染器会持续被调用以重新渲染场景。
  • queueEvent(Runnable) 方法是一种相对简单的操作。由于渲染器在独立的渲染线程里,需要使用 Java 的跨线程机制跟渲染器通讯。在 UI 线程里调用渲染器的方法可能会收到 “call to OpenGL ES API with no current context” 的警告,甚至可能导致程序崩溃。

1.2.9、public void onPause()

设置渲染模式,使用线程通信控制渲染线程暂停。

  • setRenderMode(RENDERMODE_WHEN_DIRTY):渲染器仅在 surface 创建或调用 requestRender() 时渲染。停止持续渲染,当调用 GLSurfaceView.requestRender() 时,程序再渲染屏幕。

Cocos2dxActivity 类的其他变量

1.1.3、private Cocos2dxHandler mHandler;

1.1.4、private static Cocos2dxActivity sContext = null;

1.1.5、private Cocos2dxVideoHelper mVideoHelper = null;

1.1.6、private Cocos2dxWebViewHelper mWebViewHelper = null;

Cocos2dxActivity 类的函数

1.1.7、protected void onCreate(final Bundle savedInstanceState)

  • 作用
  • 调用 protected void onLoadNativeLibraries() 加载 JNI 层的 libcocos2dcpp.so 库。
  • 使用 getPackageManager() 方法获得已安装的应用程序信息。
  • 通过 getApplicationInfo 方法获取 ApplicationInfo 对象,进而获取 AndroidManifest.xml 中的 MetaData 标签值。
  • 实例化 Cocos2dxHandler,在其构造函数中使用弱引用的方式,将该对象的成员变量 mActivity 定义为一个 Cocos2dxActivity 的实例。
  • 调用 Cocos2dxHelperinit 函数,进行相关成员变量的初始化。
  • 实例化 Cocos2dxAccelerometer,从系统服务中获得传感器管理器,获取加速重力感应的 Sensor 对象,获取屏幕介质信息和屏幕方向。
  • 实例化 Cocos2dxMusicCocos2dxSound 对象,进行相关初始化。
  • 调用 Cocos2dxHelpernativeSetContext 函数,将 Java 层的 AssetManager 传入 native 层。
  • 通过 JNI 调用 getGLContextAttrs() 方法,初始化 GLContext
  • 调用 this.init() 方法,进行界面元素的创建和设置。
  • 实例化 Cocos2dxVideoHelperCocos2dxWebViewHelper 对象。

C++ 相关知识补充

auto 关键字

auto 用来声明自动变量,是存储类型标识符,表明变量(自动)具有本地范围,块范围的变量声明(如 for 循环体内的变量声明)默认为 auto 存储类型。大多普通声明方式声明的变量都是 auto 变量,不需要明确指定 auto 关键字,默认就是 auto 的。auto 变量在离开作用域时会被程序自动释放,不会发生内存溢出情况(除了包含指针的类)。

using namespace std

using namespace std 包含标准库中的一切,使用该语句后,标准库中的元素就好像被声明为全局变量一样。但这会带来兼容性问题,因此有了不同的头文件,一个是为了兼容以前的 C++ 代码,一个是为了支持新的标准。

static 关键字

static 修饰的变量为单例。

friend 关键字

在类 A 里面加 friend class B;,使得 B 类可以访问 A 类里面的 protectedprivate 的成员函数或成员变量。但注意,在 A 里面声明了这句,只能让 B 类内部访问 A 类的保护或私有成员,反之 A 类不能访问 B 类保护或私有成员。

nullptr

如果编译器支持 nullptr,应该直接使用 nullptr 来替代 NULL 的宏定义。在正常使用过程中它们是完全等价的,但在重载或模板推导时,nullptr 能避免编译器给出错误结果。

new(std::nothrow)

new(std::nothrow) 即不抛出异常,当 new 一个对象失败时,默认设置该对象为 NULL,可以方便地通过 if(p == NULL) 来判断 new 操作是否成功。建议在 C++ 代码中,凡是涉及到 new 操作,都采用 new(std::nothrow) 然后 if(p==NULL) 的方式进行判断。

mutable 关键字

mutable 是为了突破 const 的限制而设置的。被 mutable 修饰的变量,将永远处于可变的状态,即使在一个 const 函数中。

vectorreserveresize

vectorreserve 增加了 vectorcapacity,但它的 size 没有改变。reserve 是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用 push_back()insert() 函数。而 resize 改变了 vectorcapacity 同时也增加了它的 sizeresize 是改变容器的大小,且会创建对象,因此调用这个函数之后,就可以引用容器内的对象了,加入新元素时可以用 operator[] 操作符或迭代器来引用元素对象,此时再调用 push_back() 函数,是加在这个新的空间后面的。

System.nanoTime()

System.nanoTime() 用于获取当前时间,精度为纳米级。

作者信息

menghao

menghao

共发布了 332 篇文章