私の Android アプリケーション (minSdkLevel: 2.2、targetSdkLevel: 3.0、Android 4.2 を搭載した Nexus 7 でテスト) は、読み込みフェーズで次のことを行います。
- を作成し、その上に
SoundPool
を登録しますOnLoadCompleteListener
- サウンドのロードを開始します。
SoundPool
サウンドが読み込まれるたびにコールバック メソッドを呼び出します。 - 読み込みプロセスがユーザーによって中断された場合、
SoundPool.release()
呼び出されます - (
release()
が既に呼び出されていて、以前に開始されたサウンドの読み込みが完了した場合、つまり、システムが my コールバックを呼び出した場合、アプリケーションは mySoundPool
が既に呼び出されていることを検出null
し、コールバックを無視するので安全です)。
Nexus 7 でテストすると、 SoundPool.release()
(logcat) が呼び出さ
れてから 210 ミリ秒後に次のエラーが発生しました。
つまり、イベントの順序はおそらく次のとおりです。
SoundPool.load(...)
私の呼び出しが原因で、システムがサウンドを非同期にロードし始めました- ローディング画面から出たので
SoundPool.release()
呼び出されてSoundPool
セットnull
- (?) システムは以前のサウンド読み込み完了コールバックを完了しましたが、何らかのエラーが発生しました。
AndroidソースコードとJNIコードを確認して、JNI経由でSoundPool.release()
実際に削除します。弱い参照を使用して、Java レベルで参照を格納します。SoundPool
DeleteGlobalRef
SoundPool
おそらく、非決定性のために正確な条件を再現できないため、バグを再現できません。システムは、非同期にサウンドをロードしている間にリリースされる可能性があることを正しく処理する必要SoundPool
がありますが、まれな状況でバグが発生するようです。(私のコードはSoundPool
nullcheck の後に正確に 1 回リリースされるので、エラーは確実に私のコードには含まれていないことに注意してください)。
Androidでこのようなエラーが発生する理由について何か考えはありますか? 理論的には、私の上記の疑いは正しいでしょうか? この Android バグからアプリケーションを保護するにはどうすればよいですか? たぶん、ブール値をSoundPool
解放するように設定し、すべてのコールバックが返されるまで待ってから、最後のコールバックで (このブール値に基づいて) 解放することができますか? 他の回避策は考えられませんが、少なくともうまくいくことを確認したいと思います。