मैं इस तरह मेरे एप्लिकेशन में इस मुद्दे को हल :
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);
और आखिरकार, जब आपको मीडियाप्लेयर को मारने की आवश्यकता होती है, तो आप यह सेट करने के लिए सेटसोर्स ऑब्जेक्ट की जांच करेंगे कि यह इसे रिलीज़ करने से पहले तैयार हो रहा है या नहीं। यह तैयारी कर रहा है, तो आप 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;
}
}
मैंने इसके बारे में सोचा, लेकिन मुझे यकीन नहीं है कि यह समस्या को हल करेगा। मीडियाप्लेयर डॉक्स का कहना है कि "यह ध्यान रखना महत्वपूर्ण है कि तैयारी राज्य एक क्षणिक स्थिति है, और किसी भी विधि को साइड इफेक्ट के साथ कॉल करने का व्यवहार, जबकि मीडियाप्लेयर ऑब्जेक्ट तैयारी राज्य में है, अनिश्चित है।" तो समस्या बनी रहेगी, मैं 'तैयारी' राज्य में रिलीज() को कॉल करूंगा, और परिणाम अपरिभाषित है। मुझे संदेह है कि मेरे सिंक्रोनस तैयार() के अंदर, मीडियाप्लेयर इस 'तैयारी' स्थिति में बदल जाता है और जिसके परिणामस्वरूप मुझे प्राप्त होने वाले त्रुटियों में परिणाम मिलता है। – hgm
आरेख और राज्य तालिका के अनुसार आप किसी भी राज्य से 'रिलीज() 'कॉल कर सकते हैं। इसकी कोशिश करें। मुझे लगता है कि आप सिर्फ मल्टीथ्रेडिंग संबंधित बग का सामना कर रहे हैं। और एकाधिक धागे को छोड़कर इसे "ठीक" करना चाहिए। – inazaruk
यह कहता है कि मैं किसी भी समय रिलीज() को कॉल कर सकता हूं, लेकिन अगर मैं इसे एक तैयार() के अंदर बुलाता हूं तो मुझे अटकने की समस्या का सामना करना पड़ रहा है। ऐसा नहीं होना चाहिए और एंड्रॉइड आईएमओ में एक बग है। – hgm