我的Android应用程序(minSdkLevel:2.2,targetSdkLevel:3.0,使用Android 4.2在Nexus 7上进行测试)在加载阶段执行以下操作:
SoundPool
并在其上注册OnLoadCompleteListener
SoundPool
就会调用我的回调方法。SoundPool.release()
release()
并且之前启动的声音加载完成,即系统调用我的回调,则我的应用程序检测到我的SoundPool
已经null
并忽略了回调,所以很安全)。在Nexus 7上进行测试,在SoundPool.release()
被调用(logcat)后的210ms发生以下错误:
即。事件顺序可能如下:
SoundPool.load(...)
来电SoundPool.release()
并将SoundPool
设置为null
我检查了Android源代码,SoundPool.release()
的JNI代码确实通过SoundPool
删除了JNI中的DeleteGlobalRef
。它使用弱引用来存储Java级别的SoundPool
引用。
我无法重现这个错误,可能是因为我无法重现由于不确定性导致的确切条件。系统应正确处理SoundPool
可能在异步加载声音时释放,但在极少数情况下,似乎会出现错误。 (请注意,我的代码在nullcheck之后只发布一次SoundPool
,因此错误不在我的代码中。)
在Android中出现这种错误的原因是什么?理论上,我的上述怀疑是否正确?如何保护我的应用程序免受此Android错误的影响?也许我可以尝试设置一个布尔值SoundPool
应该被释放,等待所有回调返回,然后在最后一个回调中释放它(基于这个布尔值)?我想不出任何其他的解决方法,但我想确保它至少可以工作。
答案 0 :(得分:2)
正如您所说,由于竞争条件,这似乎是Android中的一个错误。根据用户CommonsWare的要求,我在回溯中打开了一个错误:http://code.google.com/p/android/issues/detail?id=53043
违规代码似乎出现在Android的media / jni / soundpool / SoundPool.cpp中:
void SoundPool::notify(SoundPoolEvent event)
{
Mutex::Autolock lock(&mCallbackLock);
if (mCallback != NULL) {
mCallback(event, this, mUserData);
}
}
看起来mCallback是垃圾收集器可以删除的Java对象,因此当调用notify时,它会尝试引用此对象并发生“已访问已删除的全局引用”崩溃。