ti-enxame.com

Causas da Coleta de Lixo: O MediaPlayer foi finalizado sem ser lançado

Depois de muita depuração, finalmente encontrei o que está causando esse erro! Coleta de lixo!

Tenho um vídeo em exibição na mídia e, em segundo plano, procuro novos vídeos a partir de uma API Rest.

De vez em quando, vejo a coleta de lixo em execução:

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

E logo depois disso:

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

Então eu testei chamando System.gc () a cada 5 segundos.

Assim que o primeiro GC é chamado, isso acontece!

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

Por que isso acontece? Posso impedi-lo?

Reproduzindo o vídeo:

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 estiver pronto:

@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();
        }


    }
30
Harry

Eu acho que isso é porque você cria o media player dentro do escopo do método, portanto, quando o método é concluído, ele sai do escopo. Isso significa que não há referências, portanto, não há problema em coletar lixo.

Isso significa que ele pode ser liberado pelo GC antes mesmo de concluir a conclusão e, portanto, não será liberado antes de ser liberado. Em vez disso, você precisa armazenar uma referência ao media player como uma variável de membro em sua classe.

70
T. Kiley

O Java GC gerencia apenas a memória. Portanto, quando outros recursos são usados ​​(por exemplo, arquivos, soquetes etc.), você precisa gerenciá-los manualmente. No caso do MediaPlayer, o documentation menciona que:

Também é recomendável que, quando um objeto do MediaPlayer não estiver mais sendo usado, chame release () imediatamente para que os recursos usados ​​pelo mecanismo interno do player associado ao objeto MediaPlayer possam ser liberados imediatamente. O recurso pode incluir recursos singleton, como componentes de aceleração de hardware e falha na chamada de release (), podem fazer com que instâncias subseqüentes dos objetos do MediaPlayer retornem às implementações de software ou falhem completamente.

Portanto, quando você terminar uma instância do MediaPlayer, precisará certificar-se de chamar explicitamente release () nessa instância. Um bom lugar para fazer isso pode ser em um método de ciclo de vida da atividade que contém, por exemplo onDestroy (). Caso contrário, quando a instância do MediaPlayer for eventualmente coletada como lixo (em algum momento arbitrário depois que você não a fizer mais referência), o finalizador notará que você nunca chamou release () e emitirá o aviso que está vendo.

11
Jason Sankey