MediaPlayerをカスタムViewにした


MediaPlayerとか使うたびにロジック組むのがめんどくさいので、Viewにまとめた

PlayerView

MediaPlayerのカスタムビュー
1曲しか再生できない
PlayerListener:MediaPlayer.xxListenerのデリゲート
早送り、巻き戻しは5秒
SeekRunner:SeekBarのスケジューラ。誰かがAndroidでTimerは使うなとかいってたのでExecuterにしてみた
open(File file):引数のFileを再生する使う

player.xml

MediaPlayerのUI
ImageButtonはAndroid標準をそのまま使ってる
早送りボタンがスキップになってるってツッコミはなしで

MediaPlayerAvtivity

PlayerViewを使う人

使い方

  1. layout.xmlにPlayerViewを定義
  2. ロジッククラスでPlayerViewのインスタンスを取得する
  3. 再生したいFileを引数に指定してopen()メソッドを呼ぶ

これだけ

ソース

PlayerView
public class PlayerView extends FrameLayout implements OnBufferingUpdateListener, OnErrorListener,
		OnCompletionListener, OnPreparedListener, OnClickListener {

	private static final String TAG = PlayerView.class.getName();

	public static final int STATUS_PALYER_NO_START = 0;
	public static final int STATUS_PALYER_PREPARED = 1;
	public static final int STATUS_PALYER_PLAYED = 2;
	private static final int STATUS_PALYER_STOP = 3;
	private static final int ACCELERATION_VALUE = 5000;
	private static final int THREAD_RUNNING_INTERVAL = 500;

	
	private AtomicInteger statusPlayer = new AtomicInteger();
	private MediaPlayer player;

	private PlayerListener listener;
	private ImageButton buttonPlay;
	private ImageButton buttonRew;
	private ImageButton buttonFF;
	private SeekBar seekbar;
	private View rootView;
	private File streamFile;
	private int duration;
	ScheduledExecutorService scheduledEx;

	private FileInputStream fileInputStream;

	public MediaPlayer getPlayer() {
		return player;
	}

	public SeekBar getSeekbar() {
		return seekbar;
	}

	public interface PlayerListener {
		public void onPrepared();

		public void onCompletion();

		public boolean onError(int what, int extra);

		public void onBufferingUpdate(int percent);
	}

	public PlayerView(Context context) {
		super(context);
	}

	public PlayerView(Context context, AttributeSet attrs) {
		super(context, attrs);
		statusPlayer.set(STATUS_PALYER_NO_START);
		scheduledEx =  Executors.newSingleThreadScheduledExecutor();
		player = new MediaPlayer();

		initView();
	}

	private void initView() {
		LayoutInflater inflater = LayoutInflater.from(this.getContext());
		rootView = (LinearLayout) inflater.inflate(R.layout.player, null);
		addView(rootView);

		buttonPlay = (ImageButton) rootView.findViewById(R.id.button_play);
		buttonPlay.setOnClickListener(this);
		buttonRew = (ImageButton) rootView.findViewById(R.id.button_rew);
		buttonRew.setOnClickListener(this);
		buttonFF = (ImageButton) rootView.findViewById(R.id.button_ff);
		buttonFF.setOnClickListener(this);
		seekbar = (SeekBar)findViewById(R.id.seekBar1);
		seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
			}
			
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
			}
			
			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
				if (fromUser) {
					player.seekTo(progress);
				}
			}
		});
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button_play:
			play();
			break;

		case R.id.button_ff:
			ff();
			break;

		case R.id.button_rew:
			rew();
			break;
		}

	}

	private void rew() {
		int current = player.getCurrentPosition();
		player.seekTo(current - ACCELERATION_VALUE);
	}

	private void play() {
		if (player != null) {
			if (player.isPlaying()) {
				player.pause();
				buttonPlay.setImageResource(android.R.drawable.ic_media_play);
				
			} else {
				buttonPlay.setImageResource(android.R.drawable.ic_media_pause);
				player.start();
			}
		}
		if(statusPlayer.get() == STATUS_PALYER_PREPARED){
			scheduledEx.scheduleAtFixedRate(new SeekRunner("seek task"), 0, THREAD_RUNNING_INTERVAL, TimeUnit.MILLISECONDS);
			statusPlayer.set(STATUS_PALYER_PLAYED);
		}
	}
	
	public AtomicInteger getStatusPlayer() {
		return statusPlayer;
	}

	private void ff() {
		int current = player.getCurrentPosition();
		player.seekTo(current + ACCELERATION_VALUE);
	}

	public void setListener(PlayerListener listener) {
		this.listener = listener;
	}

	@Override
	public void onPrepared(MediaPlayer mp) {
		listener.onPrepared();
	}

	@Override
	public void onCompletion(MediaPlayer mp) {
		listener.onCompletion();
	}

	@Override
	public boolean onError(MediaPlayer mp, int what, int extra) {
		listener.onError(what, extra);
		return false;
	}

	@Override
	public void onBufferingUpdate(MediaPlayer mp, int percent) {
		seekbar.setSecondaryProgress(percent);
		listener.onBufferingUpdate(percent);
	}

	public void open(File file) {

		streamFile = file;
		try {
			fileInputStream = new FileInputStream(streamFile);
			player.setDataSource(fileInputStream.getFD());
			player.prepare();
			duration = player.getDuration();
			seekbar.setMax(duration);
			statusPlayer.set(STATUS_PALYER_PREPARED);

		} catch (Exception e) {
			_L.e(TAG, "open", e);
		}
	}
	
	public boolean isPlaying(){
		
		if(player == null){
			return false;
		}
		return player.isPlaying();
	}

	class SeekRunner implements Runnable{
		private String name;

		public SeekRunner(String name) {
			this.name = name;
		}


		@Override
		public void run() {
			int currentPosition = player.getCurrentPosition();
			seekbar.setProgress(currentPosition);
		}
	}
}
player.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<SeekBar
		android:id="@+id/seekBar1"
		android:layout_height="wrap_content"
		android:layout_width="fill_parent"></SeekBar>

	<LinearLayout
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:id="@+id/linearLayout1">
		<ImageButton
			android:id="@+id/button_rew"
			style="@android:style/MediaButton.Previous" />

		<ImageButton
			android:id="@+id/button_play"
			style="@android:style/MediaButton.Play" />
		<ImageButton
			android:id="@+id/button_ff"
			style="@android:style/MediaButton.Next" />

	</LinearLayout>
</LinearLayout>
MediaPlayerAvtivity
public class MediaPlayerAvtivity extends Activity {
	private File mediaFile;
	private PlayerView playerView;
	private TextView textTitle;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
		playerView = (PlayerView)findViewById(R.id.player);
		textTitle = (TextView)findViewById(R.id.text_title);
        initMediaFile();
		playerView.open(mediaFile);

    }
    
	private void initMediaFile(){
		Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
		String[] projection = { AudioColumns._ID, AudioColumns.TITLE, AudioColumns.ALBUM,
				AudioColumns.ARTIST, AudioColumns.DATA };
		String sortOrder = MediaColumns.DATE_ADDED + " DESC";
		Cursor cursor = managedQuery(uri, projection, null, null, sortOrder);
		if (cursor.moveToFirst()) {
			int idIndex = cursor.getColumnIndex(AudioColumns._ID);
			int titleIndex = cursor.getColumnIndex(AudioColumns.TITLE);
			int albumIndex = cursor.getColumnIndex(AudioColumns.ALBUM);
			int artistIndex = cursor.getColumnIndex(AudioColumns.ARTIST);
			int dataIndex = cursor.getColumnIndex(AudioColumns.DATA);
			String sdcardPath = Environment.getExternalStorageDirectory().getPath();
			if(sdcardPath != null){
				String title = cursor.getString(titleIndex);
				textTitle.setText(title);
				String mediaPath = cursor.getString(dataIndex);
				mediaFile = new File(mediaPath);
				_L.d(mediaFile.toString());
			}
		}
		cursor.close();
	}

}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<TextView
		android:id="@+id/text_title"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="@string/hello" />

	<com.hidecheck.mediaplayer.view.PlayerView
		android:id="@+id/player"
		android:layout_height="wrap_content"
		android:layout_width="fill_parent" />
</LinearLayout>