2

私の Android アプリケーション (minSdkLevel: 2.2、targetSdkLevel: 3.0、Android 4.2 を搭載した Nexus 7 でテスト) は、読み込みフェーズで次のことを行います。

  1. を作成し、その上にSoundPoolを登録しますOnLoadCompleteListener
  2. サウンドのロードを開始します。SoundPoolサウンドが読み込まれるたびにコールバック メソッドを呼び出します。
  3. 読み込みプロセスがユーザーによって中断された場合、SoundPool.release()呼び出されます
  4. (release()が既に呼び出されていて、以前に開始されたサウンドの読み込みが完了した場合、つまり、システムが my コールバックを呼び出した場合、アプリケーションは mySoundPoolが既に呼び出されていることを検出nullし、コールバックを無視するので安全です)。

Nexus 7 でテストすると、 SoundPool.release()(logcat) が呼び出さ れてから 210 ミリ秒後に次のエラーが発生しました。ログキャット

つまり、イベントの順序はおそらく次のとおりです。

  1. SoundPool.load(...)私の呼び出しが原因で、システムがサウンドを非同期にロードし始めました
  2. ローディング画面から出たのでSoundPool.release()呼び出されてSoundPoolセットnull
  3. (?) システムは以前のサウンド読み込み完了コールバックを完了しましたが、何らかのエラーが発生しました。

AndroidソースコードとJNIコードを確認して、JNI経由でSoundPool.release()実際に削除します。弱い参照を使用して、Java レベルで参照を格納します。SoundPoolDeleteGlobalRefSoundPool

おそらく、非決定性のために正確な条件を再現できないため、バグを再現できません。システムは、非同期にサウンドをロードしている間にリリースされる可能性があることを正しく処理する必要SoundPoolがありますが、まれな状況でバグが発生するようです。(私のコードはSoundPoolnullcheck の後に正確に 1 回リリースされるので、エラーは確実に私のコードには含まれていないことに注意してください)。

Androidでこのようなエラーが発生する理由について何か考えはありますか? 理論的には、私の上記の疑いは正しいでしょうか? この Android バグからアプリケーションを保護するにはどうすればよいですか? たぶん、ブール値をSoundPool解放するように設定し、すべてのコールバックが返されるまで待ってから、最後のコールバックで (このブール値に基づいて) 解放することができますか? 他の回避策は考えられませんが、少なくともうまくいくことを確認したいと思います。

4

1 に答える 1

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 が呼び出されると、このオブジェクトを参照しようとし、「accessed deleted global reference」クラッシュが発生します。

于 2013-03-09T20:57:00.550 に答える