2013-02-22 11 views
27

Dopo un sacco di debug ho finalmente trovato che cosa sta causando questo errore! Raccolta dei rifiuti!Garbage Collection causa: MediaPlayer finalizzato senza essere rilasciato

Ho un video riprodotto in visualizzazione multimediale e sullo sfondo sto cercando nuovi video da un'API di ripristino.

Ogni tanto vedo la raccolta di immondizia in esecuzione:

02-22 13:14:57.969: D/dalvikvm(16888): GC_EXPLICIT freed 152K, 4% free 6746K/6979K, paused 2ms+2ms 

E il subito dopo che:

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

Così ho provato chiamando System.gc() ogni 5 secondi.

Non appena viene chiamato il primo GC, accade!

02-22 13:19:47.813: D/dalvikvm(17060): GC_EXPLICIT freed 167K, 5% free 6745K/7047K, paused 2ms+2ms ---- I call GC 
02-22 13:19:47.813: W/MediaPlayer-JNI(17060): MediaPlayer finalized without being released ---- VIDEO PLAY INTERRUPTED 

Sono davvero nuovo per Java e Android dev, quindi per favore nudi con me!

Perché succede? Posso impedirlo?

Riproduzione video:

private void playMedia(int playListIndex) throws IOException { 
     File mediadir = getDir("tvr", Context.MODE_PRIVATE); 
     filelist = mediadir.listFiles(); 
     Log.i("media player", "play media!"); 
     String path = filelist[playListIndex].getAbsolutePath(); 
     FileInputStream fileInputStream = new FileInputStream(path); 
     final Uri uri = Uri.parse(path); 
     String filename = filelist[playListIndex].getName(); 
     if (filename.contains("image")) { 
      imageView = (ImageView)findViewById(R.id.imageView); 
      imageView.setVisibility(View.VISIBLE); 
      imageView.setImageURI(uri); 
      mHandler.postDelayed(new Runnable() { 
       public void run() { 
        imageView.setVisibility(View.GONE); 
        imageView.setImageURI(uri); 
        onCompletion(null); 
       } 
      }, 4000); 
     } else if (filename.contains("video")) { 

      MediaPlayer pl = new MediaPlayer(); 
      pl.setOnCompletionListener(this); 
      pl.setDisplay(holder); 
      pl.setDataSource(fileInputStream.getFD()); 
      pl.prepare(); 
      pl.start(); 
     } 
    } 

E quando si è fatto:

@Override 
    public void onCompletion(MediaPlayer mp) { 
     Log.i("media player", "play next please!"); 
     if (mp != null) { 
      mp.release(); 
     } 
//  play next video 
     currentMedia++; 
     if (currentMedia > playList.size() - 1) { 
      currentMedia = 0; 
     } 
     try { 
      playMedia(currentMedia); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 


    } 
+0

Potresti mostrare qualche parte di codice in cui hai implementato il mediaplayer? – Opiatefuchs

+0

Ciao, ho aggiunto il codice – Harry

risposta

65

Penso che questo sia dovuto al fatto che si crea il lettore multimediale nell'ambito del metodo, pertanto, quando il metodo viene completato, non rientra nell'ambito. Questo significa che non ci sono riferimenti, quindi è ok per la garbage collection.

Ciò significa che può essere liberato dal GC prima che abbia persino chiamatoCompletion, quindi non verrà rilasciato prima di essere cancellato. Invece, è necessario memorizzare un riferimento al lettore multimediale come variabile membro nella classe.

+1

Agghiacciante! grazie mille! questo funziona ora, sapevo che era una cosa stupida! – Harry

+0

Ho anche avuto lo stesso problema, anche se è causato dalla disattenzione dello sviluppatore, è spesso problematico trovare questo tipo di errori quando ci si trova in qualcosa ;-) Grazie! – Robert

+2

una delle migliori risposte che abbia mai letto sullo stack, al punto e estremamente intuitiva su java, scope e Gc. Grazie amico! – sirvon

11

Java GC gestisce solo la memoria. Pertanto, quando vengono utilizzate altre risorse (ad esempio file, socket, ecc.), È necessario gestirle manualmente. Nel caso di MediaPlayer, il documentation menziona che:

Si raccomanda inoltre che una volta non viene più utilizzato un oggetto MediaPlayer, chiamata rilascio() immediatamente in modo che le risorse utilizzate dal motore giocatore interna associati al MediaPlayer l'oggetto può essere rilasciato immediatamente. Le risorse possono includere risorse singleton come componenti di accelerazione hardware e l'errore di chiamata release() può causare successive istanze di oggetti MediaPlayer di fallback alle implementazioni software o fallire del tutto.

Quindi, quando hai finito con un'istanza di MediaPlayer, devi assicurarti di chiamare esplicitamente release() su quell'istanza. Un buon posto per farlo potrebbe essere in un metodo del ciclo di vita dell'attività contenente, ad es. OnDestroy(). Altrimenti, quando l'istanza di MediaPlayer viene alla fine raccolta di dati inutili (in un tempo arbitrario dopo che non la si fa più riferimento), il finalizzatore noterà che non si è mai chiamato release() e verrà visualizzato l'avviso che si sta visualizzando.

+0

Ciao, grazie! Sto chiamando release() dopo che il video ha finito di suonare – Harry

+0

Non è così, stavo chiamando release(). Succede anche prima che il primo video sia terminato, succede nei primi 5 secondi quando chiamo gc() .. – Harry

+0

Ora c'è il codice, T. Kiley ha la tua risposta. Non stai mantenendo alcun riferimento a MediaPlayer dopo averlo creato, quindi viene raccolto in anticipo. –