Подтвердить что ты не робот

Вывод мусора: MediaPlayer завершился без выпуска

После большой отладки я наконец нашел, что вызывает эту ошибку! Сбор мусора!

У меня есть видео, воспроизводящее медиа-просмотр, и в фоновом режиме я ищу новые видео из Rest API.

Время от времени я вижу, что запущена коллекция мусора:

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

И прямо после этого:

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

Итак, я тестировал его, вызывая System.gc() каждые 5 секунд.

Как только первый GC называется, это происходит!

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

Я действительно новичок в Java и Android dev, поэтому, пожалуйста, расскажите мне обо мне!

Почему это происходит? Могу ли я предотвратить это?

Воспроизведение видео:

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

И когда это будет сделано:

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


    }
4b9b3361

Ответ 1

Я думаю, это связано с тем, что вы создаете медиаплеер в рамках метода, поэтому, когда метод завершается, он выходит за рамки. Это означает, что ссылок нет, так что это нормально для сбора мусора.

Это означает, что он может быть освобожден GC до того, как он даже вызвал onCompletion, поэтому не будет освобожден до его очистки. Вместо этого вам нужно сохранить ссылку на медиаплеер в качестве переменной-члена в своем классе.

Ответ 2

Java GC управляет только памятью. Поэтому, когда используются другие ресурсы (например, файлы, сокеты и т.д.), Вам необходимо вручную их управлять. В случае с MediaPlayer в документации упоминается, что:

Также рекомендуется, чтобы после того, как объект MediaPlayer больше не используется, немедленно вызовите release(), чтобы ресурсы, используемые внутренним движком проигрывателя, связанным с объектом MediaPlayer, могли быть немедленно освобождены. Ресурс может включать в себя ресурсы singleton, такие как компоненты аппаратного ускорения и отказ в вызове release(), может привести к тому, что последующие экземпляры объектов MediaPlayer вернутся к реализации программного обеспечения или вообще не сработают.

Итак, когда вы закончили с экземпляром MediaPlayer, вам нужно убедиться, что вы явно вызываете release() в этом экземпляре. Хорошее место для этого может быть в методе жизненного цикла содержащей активности, например. OnDestroy(). В противном случае, когда этот экземпляр MediaPlayer в конечном итоге собирает мусор (в какое-то время после того, как вы больше не ссылаетесь на него), финализатор заметит, что вы никогда не вызывали release() и выведете предупреждение, которое видите.