在 Android 中,我们可以通过 android.media.MediaPlayer 类完成音频或视频文件的播放操作。需要注意的是视频和音频有许多格式,但是 MediaPlayer 类只能完成一些基本格式的操作,如果 MP3 、 3GP 等,而其他媒体格式则需要编写相应的解码器进行解码播放。
生命周期解释:
1、 Idle 状态 :当使用关键字 new 实例化一个 MediaPlayer 对象或者是调用了类中的 reset() 方法时会进入到此状态
2、 End 状态 :当调用 release() 方法之后将进入到此状态,此时会释放所有占用的硬件和软件的资源,并且不会再进入其他任何一种状态。
3、 Initialized 状态 :当 MediaPlayer 对象设置好要播放的媒体 (setDataSource()) 之后进入到此状态。
4、 Prepared 状态 :预播放状态 (prepare() 、 prepareAsync()) ,进入到此状态则表示目前的媒体文件没有任何问题,可以使用 OnPreparedListener 监听。
·如果用户调用的是 prepare() 方法(同步),则表示该 MediaPlayer 对象已经进入 Prepared 状态;
·如果用户调用的是 prepareAsync() 方法(异步),则表示该 MediaPlayer 对象进入 Preparing 状态并返回,而内部播放引擎会继续执行为完成的准备工作。
5、 Started 状态 :正在进行媒体播放 (start()) ,此时可以使用 seekTo() 方法指定媒体播放的位置。
6、 Paused 状态 :在 Started 状态下使用 Paused 状态可以暂停 MediaPlayer 的播放,暂停之后可以通过 Start() 方法将其变回到 Started 状态,继续播放。
7、 Stopped 状态 :在 Started 和 Paused 状态下都可以通过 stop() 方法停止 MediaPlayer 的播放,在 Stopped 状态下要想重新进行播放,则可以使用 prepare() 和 prepareAsync() 方法进入到就绪状态。
8、 PlaybackCompleted 状态 :当媒体文件播放完毕之后会进入此状态,用户可以使用 OnCompletionListener 监听此状态,此时可以使用 start() 方法重新播放,也可以使用 stop() 方法停止播放,或者使用 seekTo() 方法来重新定义播放位置。
9、 Error 状态: 当用户播放操作中出现某些错误(文件格式不正确、播放文件过大等)时则进入此状态,用户可以使用 OnErrorListener 来监听此状态,如果 MediaPlayer 进入此状态,可以用 reset() 方法重新变回 Idle 状态。
MP3 播放器:
MediaPlayer01_Mp3PlayerActivity.java
package com.iflytek.demo; import android.app.Activity; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; public class MediaPlayer01_Mp3PlayerActivity extends Activity { private ImageButton play = null; private ImageButton pause = null; private ImageButton stop = null; private TextView info = null; private MediaPlayer mediaPlayer = null; private SeekBar seekbar = null; private boolean playFlag = true; // 播放标记 private boolean pauseFlag = true; // 暂停标记 /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.info = (TextView) super.findViewById(R.id.info); this.play = (ImageButton) super.findViewById(R.id.play); this.pause = (ImageButton) super.findViewById(R.id.pause); this.stop = (ImageButton) super.findViewById(R.id.stop); this.seekbar = (SeekBar) super.findViewById(R.id.seekbar); this.play.setOnClickListener(new PlayOnClickListener()); this.pause.setOnClickListener(new PauseOnClickListener()); this.stop.setOnClickListener(new StopOnClickListener()); this.seekbar .setOnSeekBarChangeListener(new OnSeekBarChangeListenerImpl()); } private class UpdateSeekBar extends AsyncTask<Integer, Integer, String> { @Override protected void onPostExecute(String result) {//任务执行完后执行 super.onPostExecute(result); } @Override protected void onProgressUpdate(Integer... values) {//每次更新后的数值 MediaPlayer01_Mp3PlayerActivity.this.seekbar.setProgress(values[0]);//更新拖动条 } @Override protected String doInBackground(Integer... params) {//处理后台任务 while (MediaPlayer01_Mp3PlayerActivity.this.playFlag) { // 播放的话,进度要累加 try { Thread.sleep(params[0]);//延缓执行 } catch (InterruptedException e) { } this.publishProgress(MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer .getCurrentPosition());//修改拖动条 } return null;//返回执行结果 } } private class PlayOnClickListener implements OnClickListener { @Override public void onClick(View v) { MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer = MediaPlayer .create(MediaPlayer01_Mp3PlayerActivity.this, R.raw.hight); // 要播放的文件 if (MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer != null) { MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer.stop(); // 停止操作 } MediaPlayer01_Mp3PlayerActivity.this.seekbar .setMax(MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer .getDuration()); // 设置拖拽条的长度 UpdateSeekBar update = new UpdateSeekBar(); update.execute(500); MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer .setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { MediaPlayer01_Mp3PlayerActivity.this.playFlag = false; // 播放完毕 MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer .release(); // 释放资源 } }); try { MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer.prepare(); MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer.start(); MediaPlayer01_Mp3PlayerActivity.this.info .setText("正在播放音频文件..."); } catch (Exception e) { MediaPlayer01_Mp3PlayerActivity.this.info.setText("文件播放出现异常," + e); } } } private class PauseOnClickListener implements OnClickListener { @Override public void onClick(View v) { if (MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer != null) { if (MediaPlayer01_Mp3PlayerActivity.this.pauseFlag) { // 现在暂停 MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer.start(); MediaPlayer01_Mp3PlayerActivity.this.pauseFlag = false; } else { MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer.pause(); // 暂停 MediaPlayer01_Mp3PlayerActivity.this.pauseFlag = true; MediaPlayer01_Mp3PlayerActivity.this.info .setText("暂停音频文件..."); } } } } private class StopOnClickListener implements OnClickListener { @Override public void onClick(View v) { if (MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer != null) { MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer.stop(); // 停止 MediaPlayer01_Mp3PlayerActivity.this.info .setText("停止播放音频文件..."); } } } private class OnSeekBarChangeListenerImpl implements OnSeekBarChangeListener { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) {//进度条停止拖拽 MediaPlayer01_Mp3PlayerActivity.this.mediaPlayer.seekTo(seekBar .getProgress());//定义播放位置 } } }
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/info" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="等待音频文件播放" /> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageButton android:id="@+id/play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/play" /> <ImageButton android:id="@+id/pause" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pause" /> <ImageButton android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/stop" /> </LinearLayout> <SeekBar android:id="@+id/seekbar" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
MediaPlayer 除了可以播放音频之外,还可以播放视频,但是如果要视频,只依靠 MediaPlayer 是不够的,还需要编写一个可以用于视频显示的控件,而这块显示空间要求可以快速进行 GUI 的更新,而且可以在渲染代码时对 GUI 进行无阻塞的渲染,如果要完成此功能,则必须依靠 android.view.SurfaceView 组件, SurfaceView 组件封装了一个 Surface 对象,而不是一个 Canvas 对象,使用 Surface 可以完成对后台线程的控制,对于视频、 3D 是图形等需要快速更新或者高帧率的对象有很大的用处。
视频播放 Demo
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"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <ImageButton android:id="@+id/play" android:src="@drawable/play" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageButton android:id="@+id/stop" android:src="@drawable/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <SurfaceView android:id="@+id/surfaceView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
对于 SurfaceView 现在只是一个基本的使用,而关于它的更多应用,会在后面说拍照等功能实现的时候再深入。
如果要想操作 SurfaceView ,那么就必须对其做一些基本的设置,设置其操作类型,如果要想设置 SurfaceView 的一些参数,那么就必须依靠 SurfaceHolder 类完成。
MediaPlayer02_VideoPlayerActivity.java
package com.iflytek.demo; import android.app.Activity; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageButton; public class MediaPlayer02_VideoPlayerActivity extends Activity { private ImageButton play = null; private ImageButton stop = null; private MediaPlayer mediaPlayer = null; private SurfaceView surfaceView = null; private SurfaceHolder surfaceHolder = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.play = (ImageButton) super.findViewById(R.id.play); this.stop = (ImageButton) super.findViewById(R.id.stop); this.surfaceView = (SurfaceView) super.findViewById(R.id.surfaceView); this.surfaceHolder = this.surfaceView.getHolder();// 取得SurfaceHolder this.surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// 设置SurfaceView的类型 this.mediaPlayer = new MediaPlayer();// 创建MediaPlayer对象 try { this.mediaPlayer.setDataSource("/sdcard/test.3gp"); // 设置播放文件的路径,这里就没有判断sdcard是否存在了 } catch (Exception e) { e.printStackTrace(); } this.play.setOnClickListener(new PlayOnClickListenerImpl()); this.stop.setOnClickListener(new StopOnClickListenerImpl()); } private class PlayOnClickListenerImpl implements OnClickListener { @Override public void onClick(View v) { MediaPlayer02_VideoPlayerActivity.this.mediaPlayer .setAudioStreamType(AudioManager.STREAM_MUSIC);// 设置音频类型 MediaPlayer02_VideoPlayerActivity.this.mediaPlayer .setDisplay(MediaPlayer02_VideoPlayerActivity.this.surfaceHolder);// 设置显示区域 try { MediaPlayer02_VideoPlayerActivity.this.mediaPlayer.prepare();// 预备状态 MediaPlayer02_VideoPlayerActivity.this.mediaPlayer.start();// 播放视频 } catch (Exception e) { e.printStackTrace(); } } } private class StopOnClickListenerImpl implements OnClickListener { @Override public void onClick(View v) { MediaPlayer02_VideoPlayerActivity.this.mediaPlayer.stop();// 停止播放 } } }