33

多くのデバッグの後、私はついにこのエラーの原因を見つけました!ガベージコレクション!

メディアビューでビデオを再生していて、バックグラウンドでRestAPIから新しいビデオを探しています。

時々、ガベージコレクションが実行されているのを目にします。

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

そこで、5秒ごとにSystem.gc()を呼び出してテストしました。

最初の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

なぜこれが起こるのですか?防げますか?

ビデオの再生:

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


    }
4

2 に答える 2

72

これは、メソッドのスコープ内でメディアプレーヤーを作成するためだと思います。したがって、メソッドが完了すると、スコープ外になります。これは、参照がないことを意味するため、ガベージコレクションは問題ありません。

つまり、onCompletionを呼び出す前に、GCによって解放される可能性があるため、クリアされる前に解放されません。代わりに、メディアプレーヤーへの参照をクラスのメンバー変数として保存する必要があります。

于 2013-02-22T11:43:46.973 に答える
11

JavaGCはメモリのみを管理します。したがって、他のリソース(ファイル、ソケットなど)を使用する場合は、それらを手動で管理する必要があります。MediaPlayerの場合、ドキュメントには次のように記載されています。

MediaPlayerオブジェクトが使用されなくなったら、すぐにrelease()を呼び出して、MediaPlayerオブジェクトに関連付けられた内部プレーヤーエンジンによって使用されているリソースをすぐに解放できるようにすることもお勧めします。リソースには、ハードウェアアクセラレーションコンポーネントなどのシングルトンリソースが含まれる場合があり、release()の呼び出しに失敗すると、MediaPlayerオブジェクトの後続のインスタンスがソフトウェア実装にフォールバックするか、完全に失敗する場合があります。

したがって、MediaPlayerインスタンスを使い終わったら、そのインスタンスでrelease()を明示的に呼び出す必要があります。これを行うのに適した場所は、onDestroy()などのアクティビティを含むライフサイクルメソッドです。そうしないと、そのMediaPlayerインスタンスが最終的にガベージコレクションされると(参照しなくなった後の任意の時点で)、ファイナライザーはrelease()を呼び出さなかったことを認識し、表示されている警告を出力します。

于 2013-02-22T11:30:32.970 に答える