CCAssert(sm_pSharedApplication, "")导致程序闪退的原因以及解决方案

今天我家小管遇到一個問題,每次都是報

 
  
  1. CCApplication* CCApplication::sharedApplication()

  2. {

  3.    CCAssert(sm_pSharedApplication, "");

  4. ​    return sm_pSharedApplication;

  5. }


中的ccassert(sm_pShareApplication,"")的錯誤。百度之後發現解決方案是:


 
  
  1. Edit cocos2dxplatformandroidjniJava_org_cocos2dx_lib_Cocos2dxRenderer.cpp

  2. Line 18 to:

  3. if (CCDirector::sharedDirector()->getOpenGLView()) {

  4.    CCApplication::sharedApplication()->applicationDidEnterBackground();

  5. }

按照這方案來做之後,問題果然迎刃而解。可是我家小管問我,為什麼會這樣就不會閃退了呢?一時語塞,都不知道怎麼回答。然後按照修改的地方順藤摸瓜的慢慢的看上去發現

看了一下halloworld中的pro.android/jni/hallocpp/main.cpp 这里是我们cocos程序在android中的真正的入口。

 
  
  1. jint JNI_OnLoad(JavaVM *vm, void *reserved)

  2. {

  3.    JniHelper::setJavaVM(vm);

  4.    return JNI_VERSION_1_4;

  5. }

  6. void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)

  7. {

  8.    if (!CCDirector::sharedDirector()->getOpenGLView())

  9.    {

  10.        CCEGLView *view = CCEGLView::sharedOpenGLView();

  11.        view->setFrameSize(w, h);

  12.        AppDelegate *pAppDelegate = new AppDelegate();

  13.        CCApplication::sharedApplication()->run();

  14.    }

  15.    else

  16.    {

  17.        ccDrawInit();

  18.        ccGLInvalidateStateCache();

  19.        

  20.        CCShaderCache::sharedShaderCache()->reloadDefaultShaders();

  21.        CCTextureCache::reloadAllTextures();

  22.        CCNotificationCenter::sharedNotificationCenter()->postNotification(EVNET_COME_TO_FOREGROUND, NULL);

  23.        CCDirector::sharedDirector()->setGLDefaultValues();

  24.    }

  25.    

  26. }

JNI_OnLoad(JavaVM *vm ,void *reserved)会在System.loadLibrary("cocos2dcpp")中被调用,开始加载此libcocos2dcpp.so。在HalloWorldActivity 的onCreate方法开始正式构造我们的cocos世界。这里直接调用的Cocos2dxActivity的onCreate(final Bundle savedInstanceState)方法。


 
  
  1. @Override

  2. protected void onCreate(final Bundle savedInstanceState) {

  3. super.onCreate(savedInstanceState);  

  4. sContext = this;    

  5.     this.mHandler = new Cocos2dxHandler(this);  //新建一个cocos的消息处理器

  6.     this.init();  //此处为cocos 的真正初始化

  7. Cocos2dxHelper.init(this, this);

  8. }

Cocos2dxHandler主要处理显示Dialog的消息,Cocos2dxHelper是个辅助类,我们主要看init()方法

 
  
  1. public void init() {

  2.     // FrameLayout

  3.        ViewGroup.LayoutParams framelayout_params =

  4.            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,

  5.                                       ViewGroup.LayoutParams.FILL_PARENT);

  6.        FrameLayout framelayout = new FrameLayout(this);

  7.        framelayout.setLayoutParams(framelayout_params);

  8.        // Cocos2dxEditText layout

  9.        ViewGroup.LayoutParams edittext_layout_params =

  10.            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,

  11.                                       ViewGroup.LayoutParams.WRAP_CONTENT);

  12.        Cocos2dxEditText edittext = new Cocos2dxEditText(this);

  13.        edittext.setLayoutParams(edittext_layout_params);

  14.        // ...add to FrameLayout

  15.        framelayout.addView(edittext);

  16.        // Cocos2dxGLSurfaceView

  17.        this.mGLSurfaceView = this.onCreateView();  //创建了Cocos2dxGLSurfaceView

  18.        // ...add to FrameLayout

  19.        framelayout.addView(this.mGLSurfaceView);

  20.        // Switch to supported OpenGL (ARGB888) mode on emulator

  21.        if (isAndroidEmulator())

  22.           this.mGLSurfaceView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);

  23.        this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());

  24.        this.mGLSurfaceView.setCocos2dxEditText(edittext);

  25.        // Set framelayout as the content view

  26. setContentView(framelayout);

  27. }

this.mGLSurfaceView = this.onCreateView();创建了一个Cocos2dxGLSurfaceView对象。这个Cocos2dxGLSurfaceView对象是我们cocos的进行绘制的所需要的对象。其中有一个onSurfaceCreated()方法。onSurfaceCreated():当创建GLSurfaceView时被调用,只调用一次.在这个方法中执行只发生一次的动作,比如设置OpenGL环境参数或初始化OpenGL图形对象.

 
  
  1. @Override

  2. public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {

  3. Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);   //调用我们的main.cpp中的nativeInit方法哦

  4. this.mLastTickInNanoSeconds = System.nanoTime();

  5. }

好了找到了nativeInit的调用的位置,我们来看看nativeInit做了什么事情。

CCDirector就是是cocos2d-x中的导演类,该类在$(sourcedir)\cocos2dx\CCDirector.cpp中实现。方法sharedDirector是类CCDirector的一个静态方法,该方法用来创建游戏中唯一的CCDirector对象,代码如下:

 
  
  1. CCDirector* CCDirector::sharedDirector(void)

  2. {

  3.  if (!s_SharedDirector)

  4.  {

  5.    s_SharedDirector = new CCDisplayLinkDirector();

  6.    s_SharedDirector->init();

  7.  }

  8.  return s_SharedDirector;

  9. }


这里的CCCCDisplayLinkDirector是CCDirector的子类,方法init()做一些初始化工作:


 
  
  1. bool CCDirector::init(void)

  2. {

  3.  setDefaultValues();

  4.  //场景相关

  5.  ...

  6.  ...

  7.  //管理场景的数组栈

  8.  m_pobScenesStack = new CCArray();

  9.  m_pobScenesStack->init();

  10.  // 一些FPS等相关的成员变量初始化

  11.  ...

  12.  ...

  13.  //初始化调度器对象

  14.  m_pScheduler = new CCScheduler();

  15.  //动作管理器对象

  16.  m_pActionManager = new CCActionManager();

  17.  m_pScheduler->scheduleUpdateForTarget(m_pActionManager, kCCPrioritySystem, false);

  18.  // touchDispatcher,KeypadDispatcher,Accelerometer等对象初始化

  19.  ...

  20.  ...

  21.  // CCPoolManager中实现了cocos2d-x CCObject对象的内存管理机制

  22.  CCPoolManager::sharedPoolManager()->push();

  23.  return true;

  24. }


创建好导演对象后,Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit中调用了该对象的getOpenGLView方法:

该方法返回用于游戏绘制的CCEGLView,在init()中,m_pobOpenGLView复制为NULL。在Android平台下,这个CCEGLView其实没有什么作用,因为游戏都是绘制在Cocos2dxGLSurfaceView上的,因此方法Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit接着执行if分支:

 
  
  1. CCEGLView *view = CCEGLView::sharedOpenGLView();

  2. view->setFrameSize(w, h);


这里同样创建了游戏中类CCEGLView的唯一实例,类在$(sourcedir)\cocos2dx\platform\android\CCEGLView.cpp中实现。接着执行

 
  
  1. AppDelegate *pAppDelegate = new AppDelegate();

  2. CCApplication::sharedApplication()->run();

创建了一个类AppDelegate对象,类AppDelegate在$(sourcedir)\samples\Lua\HelloLua\Classes\AppDelegate.cpp中实现,类AppDelegate在各个平台之间共用的:

 
  
  1. class  AppDelegate : private cocos2d::CCApplication

  2. {

  3. public:

  4.  AppDelegate();

  5.  virtual ~AppDelegate();

  6.  virtual bool applicationDidFinishLaunching();

  7.  virtual void applicationDidEnterBackground();

  8.  virtual void applicationWillEnterForeground();

  9. };


该类继承自CCApplication,注意类CCApplication是在$(sourcedir)\cocos2dx\platform\android\CCApplication.cpp中实现的,它的实现是与平台相关的。创建AppDelegate实例的工作实质就是实例化CCApplication,它的构造函数代码如下:

 
  
  1. CCApplication::CCApplication()

  2. {

  3.    CCAssert(! sm_pSharedApplication, "");

  4.    sm_pSharedApplication = this;

  5. }

可是这与修改Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnPause()有什么关系呢?


Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnPause函数在Cocos2dxGLSurfaceView的handleOnPause中被调用。

 
   
  1. public void handleOnPause() {
  2. Cocos2dxRenderer.nativeOnPause();
  3. }

handleOnPause()又再Cocos2dxActivity 的OnPause()中被调用。

 
   
  1. @Override
  2. protected void onPause() {
  3. super.onPause();
  4. Cocos2dxHelper.onPause();
  5. this.mGLSurfaceView.onPause();  //此处被调用哦
  6. }

可是如果这个mGLSurfaceView还没有被new的时候Cocos2dxActivity被别的Activity 给挂起了,于是乎就会自动执行OnPause 方法,而此时CCApplication还没有被初始化,所以直接调用了

 
   
  1. CCApplication::sharedApplication()->applicationDidEnterBackground();
就用引起空指针异常,程序就会闪退了。可是CCDirector::sharedDirector()->getOpenGLView() 在上文中我们看到它是和CCApplication一起初始化的,所以只要CCDirector::sharedDirector()->getOpenGLView()为真,那么我们就可以放心的使用CCApplication啦。

你可能感兴趣的:(cocos2dx)