私はこのように私のアプリでは、この問題を解決:
は(彼らが進行中ならあなたがチェックすることができます)AsyncTasksためのオブジェクトを作成します。
private AsyncTask<String, Void, String> releaseMP;
private AsyncTask<String, Void, String> setSource;
は準備通話のためのAsyncTaskを作成します。 :
private class setSource extends AsyncTask<String, Void, String> {
@Override
protected synchronized String doInBackground(final String... urls) {
try {
mMediaPlayer.prepare();
} catch (final IllegalStateException e) {
e.printStackTrace();
return e.getMessage();
} catch (final IOException e) {
e.printStackTrace();
return e.getMessage();
} catch (final Exception e) {
e.printStackTrace();
return e.getMessage();
}
return null;
}
@Override
protected void onCancelled() {
if (setSource != null)
setSource = null;
// Send error to listener
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
releaseMP = new releaseMP().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
@Override
protected void onPostExecute(final String result) {
if (setSource != null)
setSource = null;
// Check for error result
if (result != null) {
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
}
}
@Override
protected void onPreExecute() {
}
}
今、あなたの準備コード:
try {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mDuration = -1;
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
mMediaPlayer.setDataSource(getContext(), mUri, mHeaders);
mMediaPlayer.setDisplay(mSurfaceHolder);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
// mMediaPlayer.prepareAsync();
// we don't set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
} catch (final IOException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} catch (final IllegalArgumentException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} catch (final Exception ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
}
setSource = new setSource().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
最後に、mediaPlayerを終了する必要があるときは、解放する前に準備中であるかどうかを確認するためにsetSourceオブジェクトをチェックします。それが準備されている場合は、あなたがAsyncTaskをキャンセルし、AsyncTask onCancelledでよ、あなたはリセットされ、リリース対象ます:
public void release(final boolean cleartargetstate) {
if (mMediaPlayer != null) {
if (setSource != null) {
setSource.cancel(true);
} else {
releaseMP = new releaseMP().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
}
}
をそして、これは(単にオブジェクトをリセットし、リリース)私のreleaseMP AsyncTaskです:
private class releaseMP extends AsyncTask<String, Void, String> {
@Override
protected synchronized String doInBackground(final String... urls) {
Log.i(MethodNameTest.className() + "." + MethodNameTest.methodName(), "called");
if (mMediaPlayer != null) {
// Release listeners to avoid leaked window crash
mMediaPlayer.setOnPreparedListener(null);
mMediaPlayer.setOnVideoSizeChangedListener(null);
mMediaPlayer.setOnCompletionListener(null);
mMediaPlayer.setOnErrorListener(null);
mMediaPlayer.setOnBufferingUpdateListener(null);
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
return null;
}
@Override
protected void onPostExecute(final String result) {
Log.i(MethodNameTest.className() + "." + MethodNameTest.methodName(), "called");
if (releaseMP != null)
releaseMP = null;
}
}
私はそれについて考えましたが、私はそれが手元の問題を解決することを確信していません。 MediaPlayerドキュメントには、「準備中状態は一時的な状態であり、MediaPlayerオブジェクトが準備中の状態で副作用を伴うメソッドを呼び出す動作は定義されていないことに注意することが重要です。だから、問題は残っています。私は '準備中'の状態でrelease()を呼び出し、その結果は未定義です。私は同期準備()の中で、MediaPlayerがこの「準備中」状態に移行し、それが私が受け取っているエラーを引き起こすと思われます。 – hgm
図と状態テーブルによれば、どの状態からでも 'release()'を呼び出すことができます。試してごらん。私はマルチスレッド関連のバグに直面していると思います。複数のスレッドを除外すると、それを "修正"する必要があります。 – inazaruk
私はrelease()をいつでも呼び出すことができると言っていますが、これをprepare()の中で呼び出すと、私は止まってしまうという問題に直面しています。これは起こるべきではなく、Android IMOのバグです。 – hgm