2011-12-14 14 views
6

मुझे मीडिया प्लेयर (एमपी) prepare() विधि पर अटकने के साथ एक गंभीर समस्या का सामना करना पड़ रहा है। यूआई को अवरुद्ध करने से बचने के लिए मेरा ऐप prepare() को AsyncTask में चलाता है, क्योंकि स्रोत वेब से हैं। ऐसे कई 'प्ले' बटन हैं जिन्हें उपयोगकर्ता किसी भी समय क्लिक कर सकते हैं, इसलिए मैंने एमपी 12 की स्थिति को बेहतर ढंग से नियंत्रित करने के लिए prepare() सिंक्रनाइज़ विधि के अंदर जोड़ा। मेरा ऐप इस्तेमाल किए गए संसाधनों को मुक्त करने के लिए release() पर भी कॉल करें।एंड्रॉइड मीडियाप्लेयर तैयार में फंस गया()

बात यह है कि, मैंने देखा है कि release() को तैयारी करते समय बुलाया जाता है, prepare() कभी वापस नहीं आता है, और इसलिए मैं एक सिंक्रनाइज़ विधि के अंदर फंस गया हूं। इसका सबसे बुरा यह है कि AsyncTask थ्रेड डेडलॉक में है, और हर बार जब उपयोगकर्ता उस स्थिति में खेलने पर क्लिक करता है तो एक और थ्रेड बर्बाद हो जाता है क्योंकि यह मॉनीटर को प्राप्त करने की प्रतीक्षा करता रहता है जो कभी भी prepare() की वापसी में नहीं है। जल्द ही मेरे सभी AsyncTasks धागे बर्बाद हो गए हैं और चूंकि मैं उन्हें बड़े पैमाने पर उपयोग करता हूं, मेरा ऐप काम करना बंद कर देता है।

तो मेरा सवाल है: क्या किसी को इस समस्या का सामना करने का विचार है? मैं मीडियाप्लेयर के साथ अपने सभी कामों को फिर से शुरू करने की गंभीरता से सोच रहा हूं, लेकिन मुझे पहले इस तरह की स्थितियों को संभालने का सबसे अच्छा तरीका जानने की जरूरत है।

उत्तर

3

आपको इसके बजाय prepareAsync() का उपयोग करना चाहिए। और MediaPlayer तैयारी के लिए आपको AsyncTask की आवश्यकता नहीं होगी।

+0

मैंने इसके बारे में सोचा, लेकिन मुझे यकीन नहीं है कि यह समस्या को हल करेगा। मीडियाप्लेयर डॉक्स का कहना है कि "यह ध्यान रखना महत्वपूर्ण है कि तैयारी राज्य एक क्षणिक स्थिति है, और किसी भी विधि को साइड इफेक्ट के साथ कॉल करने का व्यवहार, जबकि मीडियाप्लेयर ऑब्जेक्ट तैयारी राज्य में है, अनिश्चित है।" तो समस्या बनी रहेगी, मैं 'तैयारी' राज्य में रिलीज() को कॉल करूंगा, और परिणाम अपरिभाषित है। मुझे संदेह है कि मेरे सिंक्रोनस तैयार() के अंदर, मीडियाप्लेयर इस 'तैयारी' स्थिति में बदल जाता है और जिसके परिणामस्वरूप मुझे प्राप्त होने वाले त्रुटियों में परिणाम मिलता है। – hgm

+0

आरेख और राज्य तालिका के अनुसार आप किसी भी राज्य से 'रिलीज() 'कॉल कर सकते हैं। इसकी कोशिश करें। मुझे लगता है कि आप सिर्फ मल्टीथ्रेडिंग संबंधित बग का सामना कर रहे हैं। और एकाधिक धागे को छोड़कर इसे "ठीक" करना चाहिए। – inazaruk

+0

यह कहता है कि मैं किसी भी समय रिलीज() को कॉल कर सकता हूं, लेकिन अगर मैं इसे एक तैयार() के अंदर बुलाता हूं तो मुझे अटकने की समस्या का सामना करना पड़ रहा है। ऐसा नहीं होना चाहिए और एंड्रॉइड आईएमओ में एक बग है। – hgm

0

उस मामले के लिए Asyntasks या prepareAsync() का उपयोग करने में समस्या यह है कि यह स्वचालित रूप से तैयार होने के लिए MediaPlayer's स्थिति स्विच नहीं करता है। आपको लगता है कि यह करता है, लेकिन किसी कारण से यह नहीं करता है। मैं कुछ दिनों तक इस समस्या से फंस गया जब तक कि किसी ने मुझे OnPreparedListener लागू करने का सुझाव दिया, और इसका उपयोग मेरे MediaPlayer का उपयोग करने के लिए किया।

इसे जोड़ना काफी सरल है।

पहले, अपने वर्ग में श्रोता को लागू: (। मैं तो तुम्हारा थोड़ा भिन्न दिखाई देंगी सेवा के लिए इस का उपयोग कर रहा)

public class MusicService extends Service implements OnPreparedListener 

इसके बाद, अपने खेल में/बयान तैयार, prepareAsync उपयोग करें, और श्रोता सेट करें।

mp.prepareAsync(); 
mp.setOnPreparedListener(this); 

इसके बाद, onPrepared विधि जोड़कर उसे अपनी यात्रा का आरंभ कोड जोड़ें:

public void onPrepared(MediaPlayer mediaplayer) { 
     // We now have buffered enough to be able to play 
     mp.start(); 
    } 

कि चाल करना चाहिए।

0

सभी उत्तरों के लिए धन्यवाद, लेकिन मैंने इसे prepAsync() का उपयोग नहीं किया जैसा कि पिछले उत्तरों में बताया गया था। मुझे लगता है कि यदि तैयारी की एक तुल्यकालिक विधि उपलब्ध कराई गई थी, तो इसे सही तरीके से काम करने का एक तरीका होना चाहिए।

फिक्स, हालांकि सुरुचिपूर्ण आईएमओ नहीं है, सरल है: एक तैयार() के अंदर रिलीज() को कॉल करने से बचें। हालांकि मीडिया प्लेयर डॉक्स में राज्य आरेख का कहना है कि किसी भी राज्य में रिलीज() को बुलाया जा सकता है, प्रयोग ने साबित किया कि इसे एक तैयार() (संभवतः 'तैयारी' स्थिति में) के अंदर बुलाकर आपके ऐप को लटका दिया जाएगा। इसलिए मैंने यह देखने के लिए एक चेक जोड़ा कि क्या एमपी इस राज्य में है और अब मैं कॉलिंग रिलीज() अगर यह कर रहा हूं। मुझे यह जांचने के लिए मेरे कोड में एक बुलियन जोड़ने की ज़रूरत है, क्योंकि एमपी में कोई प्रेपरिंग() विधि नहीं है।

मुझे विश्वास है कि ऐसा नहीं होना चाहिए और एंड्रॉइड में एक बग है।टिप्पणियों में देखा जा सकता है, दस्तावेज़ों में एक विरोधाभास है: यह कहता है कि किसी भी राज्य में रिलीज() को बुलाया जा सकता है, लेकिन यह भी कहता है कि तैयारी राज्य में किसी राज्य के बदलते आदेशों को बुलाते हुए एक अनिश्चित परिणाम होता है। उम्मीद है कि यह अन्य लोगों की मदद करेगा।

private AsyncTask<String, Void, String> releaseMP; 
private AsyncTask<String, Void, String> setSource; 

तैयार कॉल के लिए एक AsyncTask बनाएँ: AsyncTasks (ताकि आप देख सकते हैं कि वे प्रगति में हैं) के लिए

बनाएं वस्तुओं:

0

मैं इस तरह मेरे एप्लिकेशन में इस मुद्दे को हल :

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; 
    } 

} 
संबंधित मुद्दे