今天我家小管遇到一個問題,每次都是報
CCApplication* CCApplication::sharedApplication()
{
CCAssert(sm_pSharedApplication, "");
return sm_pSharedApplication;
}
中的ccassert(sm_pShareApplication,"")的錯誤。百度之後發現解決方案是:
Edit cocos2dxplatformandroidjniJava_org_cocos2dx_lib_Cocos2dxRenderer.cpp
Line 18 to:
if (CCDirector::sharedDirector()->getOpenGLView()) {
CCApplication::sharedApplication()->applicationDidEnterBackground();
}
按照這方案來做之後,問題果然迎刃而解。可是我家小管問我,為什麼會這樣就不會閃退了呢?一時語塞,都不知道怎麼回答。然後按照修改的地方順藤摸瓜的慢慢的看上去發現
看了一下halloworld中的pro.android/jni/hallocpp/main.cpp 这里是我们cocos程序在android中的真正的入口。
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JniHelper::setJavaVM(vm);
return JNI_VERSION_1_4;
}
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thiz, jint w, jint h)
{
if (!CCDirector::sharedDirector()->getOpenGLView())
{
CCEGLView *view = CCEGLView::sharedOpenGLView();
view->setFrameSize(w, h);
AppDelegate *pAppDelegate = new AppDelegate();
CCApplication::sharedApplication()->run();
}
else
{
ccDrawInit();
ccGLInvalidateStateCache();
CCShaderCache::sharedShaderCache()->reloadDefaultShaders();
CCTextureCache::reloadAllTextures();
CCNotificationCenter::sharedNotificationCenter()->postNotification(EVNET_COME_TO_FOREGROUND, NULL);
CCDirector::sharedDirector()->setGLDefaultValues();
}
}
JNI_OnLoad(JavaVM *vm ,void *reserved)会在System.loadLibrary("cocos2dcpp")中被调用,开始加载此libcocos2dcpp.so。在HalloWorldActivity 的onCreate方法开始正式构造我们的cocos世界。这里直接调用的Cocos2dxActivity的onCreate(final Bundle savedInstanceState)方法。
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this;
this.mHandler = new Cocos2dxHandler(this); //新建一个cocos的消息处理器
this.init(); //此处为cocos 的真正初始化
Cocos2dxHelper.init(this, this);
}
Cocos2dxHandler主要处理显示Dialog的消息,Cocos2dxHelper是个辅助类,我们主要看init()方法
public void init() {
// FrameLayout
ViewGroup.LayoutParams framelayout_params =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT);
FrameLayout framelayout = new FrameLayout(this);
framelayout.setLayoutParams(framelayout_params);
// Cocos2dxEditText layout
ViewGroup.LayoutParams edittext_layout_params =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
Cocos2dxEditText edittext = new Cocos2dxEditText(this);
edittext.setLayoutParams(edittext_layout_params);
// ...add to FrameLayout
framelayout.addView(edittext);
// Cocos2dxGLSurfaceView
this.mGLSurfaceView = this.onCreateView(); //创建了Cocos2dxGLSurfaceView
// ...add to FrameLayout
framelayout.addView(this.mGLSurfaceView);
// Switch to supported OpenGL (ARGB888) mode on emulator
if (isAndroidEmulator())
this.mGLSurfaceView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);
this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
this.mGLSurfaceView.setCocos2dxEditText(edittext);
// Set framelayout as the content view
setContentView(framelayout);
}
this.mGLSurfaceView = this.onCreateView();创建了一个Cocos2dxGLSurfaceView对象。这个Cocos2dxGLSurfaceView对象是我们cocos的进行绘制的所需要的对象。其中有一个onSurfaceCreated()方法。onSurfaceCreated():当创建GLSurfaceView时被调用,只调用一次.在这个方法中执行只发生一次的动作,比如设置OpenGL环境参数或初始化OpenGL图形对象.
@Override
public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {
Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight); //调用我们的main.cpp中的nativeInit方法哦
this.mLastTickInNanoSeconds = System.nanoTime();
}
好了找到了nativeInit的调用的位置,我们来看看nativeInit做了什么事情。
CCDirector就是是cocos2d-x中的导演类,该类在$(sourcedir)\cocos2dx\CCDirector.cpp中实现。方法sharedDirector是类CCDirector的一个静态方法,该方法用来创建游戏中唯一的CCDirector对象,代码如下:
CCDirector* CCDirector::sharedDirector(void)
{
if (!s_SharedDirector)
{
s_SharedDirector = new CCDisplayLinkDirector();
s_SharedDirector->init();
}
return s_SharedDirector;
}
这里的CCCCDisplayLinkDirector是CCDirector的子类,方法init()做一些初始化工作:
bool CCDirector::init(void)
{
setDefaultValues();
//场景相关
...
...
//管理场景的数组栈
m_pobScenesStack = new CCArray();
m_pobScenesStack->init();
// 一些FPS等相关的成员变量初始化
...
...
//初始化调度器对象
m_pScheduler = new CCScheduler();
//动作管理器对象
m_pActionManager = new CCActionManager();
m_pScheduler->scheduleUpdateForTarget(m_pActionManager, kCCPrioritySystem, false);
// touchDispatcher,KeypadDispatcher,Accelerometer等对象初始化
...
...
// CCPoolManager中实现了cocos2d-x CCObject对象的内存管理机制
CCPoolManager::sharedPoolManager()->push();
return true;
}
创建好导演对象后,Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit中调用了该对象的getOpenGLView方法:
该方法返回用于游戏绘制的CCEGLView,在init()中,m_pobOpenGLView复制为NULL。在Android平台下,这个CCEGLView其实没有什么作用,因为游戏都是绘制在Cocos2dxGLSurfaceView上的,因此方法Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit接着执行if分支:
CCEGLView *view = CCEGLView::sharedOpenGLView();
view->setFrameSize(w, h);
这里同样创建了游戏中类CCEGLView的唯一实例,类在$(sourcedir)\cocos2dx\platform\android\CCEGLView.cpp中实现。接着执行
AppDelegate *pAppDelegate = new AppDelegate();
CCApplication::sharedApplication()->run();
创建了一个类AppDelegate对象,类AppDelegate在$(sourcedir)\samples\Lua\HelloLua\Classes\AppDelegate.cpp中实现,类AppDelegate在各个平台之间共用的:
class AppDelegate : private cocos2d::CCApplication
{
public:
AppDelegate();
virtual ~AppDelegate();
virtual bool applicationDidFinishLaunching();
virtual void applicationDidEnterBackground();
virtual void applicationWillEnterForeground();
};
该类继承自CCApplication,注意类CCApplication是在$(sourcedir)\cocos2dx\platform\android\CCApplication.cpp中实现的,它的实现是与平台相关的。创建AppDelegate实例的工作实质就是实例化CCApplication,它的构造函数代码如下:
CCApplication::CCApplication()
{
CCAssert(! sm_pSharedApplication, "");
sm_pSharedApplication = this;
}
可是这与修改Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnPause()有什么关系呢?
Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnPause函数在Cocos2dxGLSurfaceView的handleOnPause中被调用。
public void handleOnPause() {
Cocos2dxRenderer.nativeOnPause();
}
handleOnPause()又再Cocos2dxActivity 的OnPause()中被调用。
@Override
protected void onPause() {
super.onPause();
Cocos2dxHelper.onPause();
this.mGLSurfaceView.onPause(); //此处被调用哦
}
可是如果这个mGLSurfaceView还没有被new的时候Cocos2dxActivity被别的Activity 给挂起了,于是乎就会自动执行OnPause 方法,而此时CCApplication还没有被初始化,所以直接调用了
CCApplication::sharedApplication()->applicationDidEnterBackground();