现象描述:
cocos2d-x游戏移植android平台,运行时出现闪退,log如下:
06-17 13:12:25.020: E/AndroidRuntime(8053): FATAL EXCEPTION: GLThread 273 06-17 13:12:25.020: E/AndroidRuntime(8053): java.util.ConcurrentModificationException 06-17 13:12:25.020: E/AndroidRuntime(8053): at java.util.HashMap$HashIterator.nextEntry(HashMap.java:792) 06-17 13:12:25.020: E/AndroidRuntime(8053): at java.util.HashMap$KeyIterator.next(HashMap.java:819) 06-17 13:12:25.020: E/AndroidRuntime(8053): at org.cocos2dx.lib.Cocos2dxSound.stopEffect(Cocos2dxSound.java:176) 06-17 13:12:25.020: E/AndroidRuntime(8053): at org.cocos2dx.lib.Cocos2dxHelper.stopEffect(Cocos2dxHelper.java:185) 06-17 13:12:25.020: E/AndroidRuntime(8053): at org.cocos2dx.lib.Cocos2dxRenderer.nativeRender(Native Method) 06-17 13:12:25.020: E/AndroidRuntime(8053): at org.cocos2dx.lib.Cocos2dxRenderer.onDrawFrame(Cocos2dxRenderer.java:94) 06-17 13:12:25.020: E/AndroidRuntime(8053): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516) 06-17 13:12:25.020: E/AndroidRuntime(8053): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
原因分析:
查看Cocos2dxSound.java的176行stopEffect方法
public void stopEffect(final int pStreamID) {
this.mSoundPool.stop(pStreamID);
// remove record
for (final String pPath : this.mPathStreamIDsMap.keySet()) {
if (this.mPathStreamIDsMap.get(pPath).contains(pStreamID)) {
this.mPathStreamIDsMap.get(pPath).remove(this.mPathStreamIDsMap.get(pPath).indexOf(pStreamID));
break;
}
}
}
我们注意到,在迭代时有remove操作,即进行了结构修改(增删操作),快速失败,因此抛出了ConcurrentModificationException.
解决方法:
由于我的游戏里的这个音效频繁播放,所以我用pauseEffect替代了stopEffect,一个偷懒的方案.
彻底的解决方法:
1).使用iterator来修改vector
2).使用conCurrentHashMap替代HashMap
扩展阅读:
快速失败:指某个线程在迭代vector的时候,不允许其他线程对vector进行结构性修改(增删操作,改值不算),如有修改,会抛出ConcurrentModificationException异常.
比如用iterator迭代userCollect时,iterator即另外起的一个线程,如果此时用userCollect.remove(obj)修改userCollect时,就会立刻抛出异常报错,不会等迭代结束才报错.
即时是单线程里,也是这样的.