2012-04-03 5 views
11

Sto provando a utilizzare la classe MediaPlayer di Android per riprodurre alcuni suoni.Impossibile ottenere Android MediaPlayer onCompletion per attivare

Ecco il codice

MediaPlayer mp = new MediaPlayer(); 
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
      public void onCompletion(MediaPlayer mp) { 
       Log.i(LOGTAG, "onComplete hit"); 
       mp.stop(); 
       mp.release(); 
      } 
    });   

mp.prepare(); 
mp.start(); 

Questo codice viene eseguito in un servizio, ma per qualche motivo il suono gioca ok, ma niente inserito nel onCompletion non sembra al fuoco. Poi ricevo un messaggio nel logcat che il mediaplayer non è stato rilasciato. Sono in perdita per quello che ho sbagliato in questo.

Sto eseguendo questo test su una rom di galassia nexus 4.0.4.

Ho anche notato che il suono può essere tagliato alla fine.

risposta

3

Ecco come ce l'ho:

video.setOnCompletionListener(this); 
    IntroClip.execute(video); 
} 

@Override 
public void onCompletion(MediaPlayer mp){ 
    Button LoginButton; 
    Button CreateAccount; 
    Button RecoverPass; 

    setContentView(R.layout.loginmenu); 
    Spin = (ProgressBar)findViewById(R.id.Spinner); 

    mp.release();  
} 
+0

Immagino che "video" sia un'istanza di MediaPlayer? e che hai un "implementa MediaPlayer.OnCompletionListener" nella tua classe? Ho provato anche questo metodo ma non ha funzionato. – Andrew

+2

@Andrew Come è accettata la risposta, se non ha funzionato? L'hai fatto funzionare? Se sì, come? – hendrix

+2

@smitalm call start() prima di impostare il listener. – ajacian81

26

In realtà è semplice (ma stupido). Imposta il tuo ascoltatore dopo che si chiama start(), in questo modo:

ediaPlayer mp = new MediaPlayer(); 
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.prepare(); 
mp.start(); 
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
      public void onCompletion(MediaPlayer mp) { 
       Log.i(LOGTAG, "onComplete hit"); 
       mp.stop(); 
       mp.release(); 
      } 
    });   
+3

Puoi spiegare perché chiamare start() prima di impostare il listener di completamento è importante? È un capriccio di Android? –

+0

@FabianTamp è un altro capriccio di Android. Potrebbe non essere richiesto per tutti i dispositivi (o anche più), ma al momento era decisamente una soluzione per il problema. – ajacian81

+1

Non sono riuscito a vedere alcuna prova per supportare il motivo per cui ciò risolvesse le cose nella sorgente Android, comunque. Risulta che il problema principale per me era che il MediaPlayer era GC, prima che finisse di giocare, ho aggiunto una risposta che delinea più in dettaglio :) –

1

stavo incontrando sintomi simili a questa, e la causa principale è stata che il MediaPlayer stavo garbage collection prima della OnCompletionListener era stato chiamato.

A giudicare dal tuo codice, sembra lo stesso problema: il tuo codice non contiene un riferimento longevo al MediaPlayer, quindi non appena tale funzione termina (e prima che l'audio termini la riproduzione) MediaPlayer sia suscettibile a GC.

Questo problema è identificabile da questa linea di registro:

02-22 13:14:57.969: W/MediaPlayer-JNI(16888): MediaPlayer finalized without being released 

È possibile risolvere il problema da riprogettare la classe in modo tale che il riferimento MediaPlayer è mantenuto più a lungo - memorizzando un riferimento ad essa nell'attività, e il riutilizzo la stessa istanza per suonare lo stesso suono più volte, per esempio.

C'è una spiegazione più dettagliata qui: Garbage Collection causes : MediaPlayer finalized without being released

0

Ci sono due approcci per inizializzare l'oggetto MediaPlayer, "nuovo" e "Create()". Per fare OnCompletionListener, è diverso per gli oggetti ottenuti in questi due approcci.

1) il "nuovo" approccio

MediaPlayer mp = new MediaPlayer(); 
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.prepare(); 
mp.start(); 
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
    public void onCompletion(MediaPlayer mp) { 
     Log.i(LOGTAG, "onComplete hit"); 
     mp.stop(); 
     mp.release(); 
    } 
}); 

2) il metodo di "creare"

MediaPlayer mp = MediaPlayer.create(getActivity(), Uri.parse(soundUrl)); 
//mp.prepare() is not needed here 
mp.setLooping(false); 
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){ 
    @Override 
    public void onCompletion(MediaPlayer mp) { 
     Log.i(LOGTAG, "onComplete hit"); 
     mp.stop(); 
     mp.release(); 
    } 
}); 

Per il metodo create(), ho sperimentato il problema simile. Se mp.prepare() viene chiamato dopo aver chiamato create(), la procedura non arriverà mai al seguente setOnCompletionListener, nemmeno a start(). Il motivo essenziale è che "gli oggetti si trovano nello stato Preparato se la creazione utilizzando il metodo di creazione ha esito positivo" (https://developer.android.com/reference/android/media/MediaPlayer.html). Quindi non è necessario chiamare il prepare() dopo aver usato il metodo create().

0

In realtà, il motivo è che MediaPlayer è una variabile locale. Al termine della funzione, MediaPlayer viene raccolto da GC. Quindi la correzione è semplice, rendi il tuo MediaPlayer un membro della classe.

YourClassName { 
    MediaPlayer mp = new MediaPlayer(); 

    void YourFunction() { 
      mp.setDataSource(context, Uri.parse(soundUrl)); 
      mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
      mp.setLooping(false); 
      mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
       @Override 
       public void onCompletion(MediaPlayer mp) { 
        Log.i(LOGTAG, "onComplete hit"); 
        mp.stop(); 
        mp.release(); 
       } 
      });   
      mp.prepare(); 
      mp.start(); 
    } 
}