復(fù)現(xiàn)步驟:
1.安裝好apk
2.啟動(dòng)app -> Splash頁(yè)面 -> 申請(qǐng)授權(quán)彈窗
3.同意或者拒接 -> 退出彈窗 -> 屏幕閃爍
Log:
運(yùn)行中出現(xiàn)GL Error 0x0506
初步排查發(fā)現(xiàn)導(dǎo)致該問題的原因是CCDirector::mainLoop()
函數(shù)中 _invalid
標(biāo)識(shí)為true
導(dǎo)致未執(zhí)行 drawScene()
方法:
void Director::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (_restartDirectorInNextLoop)
{
_restartDirectorInNextLoop = false;
restartDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
排查為什么_invalid
標(biāo)識(shí)會(huì)變?yōu)?code>true萤悴,發(fā)現(xiàn)修改該變量的地方為:
void Director::startAnimation()
{
_invalid = false;
}
void Director::stopAnimation()
{
_invalid = true;
}
繼續(xù)往下哟忍!
// AppDelegate.cpp
void AppDelegate::applicationDidEnterBackground()
{
Director::getInstance()->stopAnimation();
}
void AppDelegate::applicationWillEnterForeground()
{
Director::getInstance()->startAnimation();
}
// Java_org_cocos2dx_lib_Cocos2dxRenderer.cpp
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnResume() {
static bool firstTime = true;
if (Director::getInstance()->getOpenGLView()) {
// don't invoke at first to keep the same logic as iOS
// can refer to https://github.com/cocos2d/cocos2d-x/issues/14206
if (!firstTime)
Application::getInstance()->applicationWillEnterForeground();
firstTime = false;
}
}
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnPause() {
if (Director::getInstance()->getOpenGLView()) {
Application::getInstance()->applicationDidEnterBackground();
}
}
// Cocos2dxRenderer.java
public void handleOnPause() {
Cocos2dxRenderer.nativeOnPause();
}
public void handleOnResume() {
Cocos2dxRenderer.nativeOnResume();
}
// Cocos2dxGLSurfaceView.java
@Override
public void onResume() {
Log.d(TAG, "onResume()");
super.onResume();
this.setRenderMode(RENDERMODE_CONTINUOUSLY);
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnResume();
}
});
}
@Override
public void onPause() {
Log.d(TAG, "onPause()");
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnPause();
}
});
this.setRenderMode(RENDERMODE_WHEN_DIRTY);
// super.onPause();
}
由此我們可以得出結(jié)論,是因?yàn)槭跈?quán)彈窗彈出觸發(fā)Cocos2dxGLSurfaceView.onPause()
方法,導(dǎo)致_invalid
為true
那么問題來(lái)了,為什么彈框消失的時(shí)候觸發(fā)的Cocos2dxGLSurfaceView.onResume()
不會(huì)把_invalid
還原為false
呢?
根據(jù)流程我發(fā)現(xiàn)Cocos2d引擎源碼在Java_org_cocos2dx_lib_Cocos2dxRenderer.java
的JNI函數(shù)JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnResume()
方法里設(shè)置了一個(gè)靜態(tài)變量static bool firstTime = true;
當(dāng)?shù)谝淮螆?zhí)行該函數(shù)的時(shí)候會(huì)跳過(guò)執(zhí)行applicationWillEnterForeground()
方法避乏,那么我們接下來(lái)只需要判斷彈框消失后觸發(fā)的Cocos2dxGLSurfaceView.onResume()
是不是程序運(yùn)行的第一次調(diào)用,而測(cè)試結(jié)果確實(shí)如此8噬!E钠ぁ!
到此跑杭,我們定位到了該問題的產(chǎn)生邏輯铆帽,那么接下來(lái)如何解決這個(gè)問題就簡(jiǎn)單多了。
解決思路選擇其中之一即可:
1.在JNI方法JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnResume()
中做特殊處理:
定義布爾類型類成員變量bool isPause = false
,當(dāng)執(zhí)行nativeOnPause()
時(shí)把isPause
置為true
,再添加判斷條件
if (!firstTime || isPause)
2.在Cocos2dxActivity
中處理:
private void resumeIfHasFocus() {
if(hasFocus) { // 取消hasFocus判斷條件
this.hideVirtualButton();
Cocos2dxHelper.onResume();
mGLSurfaceView.onResume();
}
}
當(dāng)然還有其他解決思路德谅,同時(shí)爹橱,不同的項(xiàng)目上述的解決方案可能會(huì)導(dǎo)致一些其他問題,需要根據(jù)具體項(xiàng)目測(cè)試窄做。