Android学习11-----多媒体技术(3) 媒体播放

 

         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();// 停止播放
		}

	}
}