shivaq
11/19/2016 - 9:36 AM

MediaPlayer の onStop などのライフサイクル制御

MediaPlayer の onStop などのライフサイクル制御

package com.example.android.miwok;


import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.NavUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * A simple {@link Fragment} subclass.
 */
public class NumbersFragment extends Fragment {
    private MediaPlayer mMediaPlayer;
    private AudioManager mAudioManager;

    /**
     * on completion Listener コールバックをインスタンス化。これで、再利用できる。
     */
    private MediaPlayer.OnCompletionListener mCompletionListener =
            new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    releaseMediaPlayer();
                }
            };

    //Listener インターフェイス をインスタンス化 ※ クラスに implement もできるけれども。
    private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            switch (focusChange) {
                case AudioManager.AUDIOFOCUS_GAIN:
                    mMediaPlayer.start();
                    break;

                case AudioManager.AUDIOFOCUS_LOSS:
                    if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
                    break;

                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
                    mMediaPlayer.seekTo(0);//短いファイルなので、最初から再生
                    break;
            }
        }
    };//Listener インターフェイス をインスタンス化 終了

    public NumbersFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {


        final ArrayList<Word> words = new ArrayList<>();
        words.add(new Word("one", "lutti", R.raw.number_one, R.drawable.number_one));
        words.add(new Word("two", "otiiko", R.raw.number_two, R.drawable.number_two));
        words.add(new Word("three", "tolookosu", R.raw.number_three, R.drawable.number_three));
        words.add(new Word("four", "oyyisa", R.raw.number_four, R.drawable.number_four));
        words.add(new Word("five", "massokka", R.raw.number_five, R.drawable.number_five));
        words.add(new Word("six", "temmokka", R.raw.number_six, R.drawable.number_six));
        words.add(new Word("seven", "kenekaku", R.raw.number_seven, R.drawable.number_seven));
        words.add(new Word("eight", "kawinta", R.raw.number_eight, R.drawable.number_eight));
        words.add(new Word("nine", "wo’e", R.raw.number_nine, R.drawable.number_nine));
        words.add(new Word("ten", "na’aacha", R.raw.number_ten, R.drawable.number_ten));

        //カスタムAdapterを生成
        //変更3.Fragment は Adapter に渡すコンテキストになれないので、
        //this ではなく Fragment を内包する Activity をコンテキストとして渡す
        WordAdapter adapter = new WordAdapter(getActivity(), words, R.color.category_numbers);

        View rootView = inflater.inflate(R.layout.word_list, container, false);

        //コンテナとして、ListView を使用
        //変更1.Fragment には findViewById メソッドがないため、rootView OBJ に対して行うような形をとる
        ListView listView = (ListView) rootView.findViewById(R.id.list);
        listView.setAdapter(adapter);


        //AudioManager の初期化
        //変更2. Fragment は System サービスへのサクセスがないため、
//        まず Fragment を 内包するActivity の OBJ を取得し、それに対してgetSystemService する。
        mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Word word = words.get(position);

//              他のAudioとの再生重複回避のため、 MediaPlayer が クリエイトされる前に、一度リリースする。
                releaseMediaPlayer();


                //Audio Focus をリクエスト
                int audioGetResult = mAudioManager.requestAudioFocus(mAudioFocusChangeListener,
                        AudioManager.STREAM_MUSIC,
                        //短い音声ファイルのため、一時的な duration
                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

                //Audio Focus が取得できていたら、再生
                if (audioGetResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {

                    //メディアプレイヤー 生成//取得できなきゃ生成もいらん
                    //変更4. 内包するActivityを、コンテキストとして渡す用に変える
                    mMediaPlayer = MediaPlayer.create(getActivity(),
                            word.getMiwokPronounciation());

                    //メディアプレイヤー 再生
                    mMediaPlayer.start();

                    //Listener の new は インスタンス変数にて定義済み
                    //再生完了時にリソースがリリースされるよう定義
                    mMediaPlayer.setOnCompletionListener(mCompletionListener);
                }

                Log.v("NumbersFragment", "Current word: " + word);//こんな感じで挟み込む
            }
        });
        //▼変更5.追加
        return rootView;
    }


    @Override
    public void onStop() {//Activity の方では、onStop は protected だった。
        super.onStop();
        releaseMediaPlayer();
    }

    /**
     * リソースを解放し、MediaPlayer をクリーンアップ
     * null なのに release() を試みたりしないように配慮したロジック。
     */
    private void releaseMediaPlayer() {
        if (mMediaPlayer != null) {
            mMediaPlayer.release();
            mMediaPlayer = null;

            //Audio Focus を破棄(Listener を unregister している)
            mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
        }
    }
}