MediaPlayer详解

大家好我们今天研究的是Android中很重要也最为复杂的媒体播放器---MediaPlayer.

Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的。

首先来看看MediaPlayer的生命周期:



从MediaPlayer的生命周期图或者说是状态转移图上来看:

  1. 当一个MediaPlayer对象别创建或者调用reset()方法之后,它处于空闲状态,在调用release()方法后,才会处于结束状态。
    • 一个新建的MediaPlayer对象在调用getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int), setLooping(boolean), setVolume(float,float), pause(), start(), stop(), seekTo(int), prepare(), prepareAsync()方法时,不会触发OnErrorListener.onError()事件,但是MediaPlayer对象如果调用了reset()方法后,再使用这些方法则会触发OnErrorListener.onError()事件。
    • 当MediaPlayer对象不再被使用时,最好通过release()方法来释放,使其处于结束状态,以免造成不必要的错误。当MediaPlayer处于结束状态是,便不能再使用。
    • MediaPlayer对象被新建时处于空闲状态,如果通过creat()方法创建之后便处于准备状态。
  2. 一般情况下,一些常用的播放控制操作可能因为音频、视频的格式不被支持或者质量较差以及流超时,也有可能由于开发者的疏忽使得MediaPlayer对象处于无效状态而导致错误。这时可以通过注册setOnErrorListener()方法实现OnErrorListener.onError()方法来监控这些错误。如果发生了错误,MediaPlayer对象将处于错误状态,可以使用reset()方法来恢复错误。
  3. 任何MediaPlayer对象都必须先处于准备状态,然后才开始播放。
  4. 要开始播放MediaPlayer对象都必须成功调用start()方法。可以通过isPlaying()方法来检测当前是否正在播放。
  5. 当MediaPlayer对象在播放时,可以进行暂停和停止等操作,pause()方法暂停播放,stop()方法停止播放。处于暂停状态时可以通过start()方法来恢复播放,但是处于停止状态则必须先调用pause()方法处于准备状态,然后再通过start()方法来开始播放。
  6. 可以通过setLooping(boolean)方法来设置是否循环播放。

下边是MediaPlayer提供的常用方法:

方法 说明
MediaPlayer 构造方法
create 创建一个要播放的多媒体
getCurrentPosition 得到当前播放位置
getDuration 得到文件的时间
getVideoHeight 得到视频的高度
getVideoWidth 得到视频的宽度
isLooping 是否循环播放
isPlaying 是否正在播放
pause 暂停
prepare 准备(同步)
prepareAsync 准备(异步)
release 释放MediaPlayer对象
reset 重置MediaPlayer对象
seekTo 指定播放的位置(以毫秒为单位的时间)
setAudioStreamType 设置流媒体的类型
setDataSource 设置多媒体数据来源
setDisplay 设置用SurfaceHolder来显示多媒体
setLooping 设置是否循环播放
setOnButteringUpdateListener 网络流媒体的缓冲监听
setOnErrorListener 设置错误信息监听
setOnVideoSizeChangedListener 视频尺寸监听
setScreenOnWhilePlaying 设置是否使用SurfaceHolder来保持屏幕显示
setVolume 设置音量
start 开始播放
stop 停止播放

至此,可以得出Android中通过MediaPlayer来播放音乐的步骤:

 MediaPlayer mp = new MediaPlayer();//构建MediaPlayer对象
 mp.setDataSource("/sdcard/test.mp3");//设置文件路径
 mp.prepare();//准备
 mp.start();//开始播放


  MediaPlayer在底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个MediaPlayer程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。

而我们今天的例子只是利用MediaPlayer来播放res/raw文件夹中一首非常动听的英文哥Avril Lavigne - Complicated.mp3.程序有4个ImageButton按钮,播放,停止,重播和暂停!4个按钮的功能我就不用多说.下面我将Step By Step教你如何完成本Demo的实现.本实例可以实现音乐播放器除了来电的时候会暂停播放,通话结束后恢复播放外,打开其他的Activity都可以继续播放音乐,享受一边听音乐一边做其他的事情。

Step 1 :新建一个Android工程,命名为AudioPlayer



Step 2 :准备素材,将Avril Lavigne - Complicated.mp3导入到SDCard中


Step 3: 设计UI布局,在main.xml里放入4个ImageButton,代码如下:

<?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:layout_width="wrap_content"
		android:layout_height="40dp" android:text="@string/file_name"
		android:id="@+id/textView" />
	<EditText android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:id="@+id/file_name" 
		android:text="Avril Lavigne - Complicated.mp3"/>
	<LinearLayout android:orientation="horizontal"
		android:layout_width="fill_parent" android:layout_height="wrap_content">
		<Button android:layout_width="wrap_content"
			android:layout_height="wrap_content" android:text="@string/button_play"
			android:onClick="mediaPlay" android:id="@+id/button_play" />

		<Button android:layout_width="wrap_content"
			android:layout_height="wrap_content" android:text="@string/button_pause"
			android:onClick="mediaPlay" android:id="@+id/button_pause" />

		<Button android:layout_width="wrap_content"
			android:layout_height="wrap_content" android:text="@string/button_replay"
			android:onClick="mediaPlay" android:id="@+id/button_replay" />

		<Button android:layout_width="wrap_content"
			android:layout_height="wrap_content" android:text="@string/button_stop"
			android:onClick="mediaPlay" android:id="@+id/button_stop" />
	</LinearLayout>
</LinearLayout>

string.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, MainActivity!</string>
    <string name="app_name">音乐播放器</string>
    <string name="file_name">请输入音乐文件名</string>
    <string name="file_noexist">音乐文件不存在</string>
    <string name="button_play">播放</string>
    <string name="button_pause">暂停</string>
    <string name="button_continue">继续</string>
    <string name="button_replay">重播</string>
    <string name="button_stop">停止</string>
</resources>


Step 4 :主控制程序MainActivity.java的实现,代码如下:

package cn.roco.mp3;

import java.io.File;

import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	private TextView textView;
	private EditText file_name_Text;
	private String filePath;
	private MediaPlayer mediaPlayer;
	private boolean pause;
	private int playPosition;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		textView=(TextView) this.findViewById(R.id.textView);
		file_name_Text = (EditText) this.findViewById(R.id.file_name);
		mediaPlayer = new MediaPlayer();
		
		TelephonyManager telephonyManager=(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		telephonyManager.listen(new MyPhoneListener(), PhoneStateListener.LISTEN_CALL_STATE);
	}
	/**
	 * 只有电话来了之后才暂停音乐的播放
	 */
	private final class MyPhoneListener extends android.telephony.PhoneStateListener{
		@Override
		public void onCallStateChanged(int state, String incomingNumber) {
			switch (state) {
			case TelephonyManager.CALL_STATE_RINGING://电话来了
				if (mediaPlayer.isPlaying()) {
					playPosition = mediaPlayer.getCurrentPosition();// 获得当前播放位置
					mediaPlayer.stop();
				}
				break;
			case TelephonyManager.CALL_STATE_IDLE: //通话结束
				if (playPosition > 0 && filePath != null) {
					play(playPosition);
					playPosition = 0;
				}
				break;
			}
			
		}
	}
	
	/*
	// 当该窗口处于不可见的时候触发
	@Override
	protected void onPause() {
		if (mediaPlayer.isPlaying()) {
			playPosition = mediaPlayer.getCurrentPosition();// 获得当前播放位置
			mediaPlayer.stop();
		}
		super.onPause();
	}

	// 当该窗口处于重新回到前台时候触发
	@Override
	protected void onResume() {
		if (playPosition > 0 && filePath != null) {
			play();
			mediaPlayer.seekTo(playPosition);
			playPosition = 0;
		}
		super.onResume();
	}
	*/
	
	@Override
	protected void onDestroy() {
		mediaPlayer.release();
		mediaPlayer = null;
		super.onDestroy();
	}

	public void mediaPlay(View v) {
		switch (v.getId()) {
		// 播放按钮
		case R.id.button_play:
			String fileName = file_name_Text.getText().toString();
			File audio = new File(Environment.getExternalStorageDirectory(),
					fileName);
			if (audio.exists()) {// 文件存在
				filePath = audio.getAbsolutePath(); // 文件绝对路径
				play(0); // 播放音乐
				textView.setText("音乐开始播放...");
			} else {
				filePath = null;
				Toast.makeText(getApplicationContext(), R.string.file_noexist,
						1).show();
			}
			break;
		// 暂停按钮
		case R.id.button_pause:
			if (mediaPlayer.isPlaying()) {// 如果正在播放
				mediaPlayer.pause();// 暂停
				pause = true;
				textView.setText("音乐暂停播放...");  
				((Button) v).setText(R.string.button_continue);// 文字:暂停-->继续
			} else {
				if (pause) {// 如果处于暂停状态
					mediaPlayer.start();// 继续播放
					pause = false;
					textView.setText("音乐继续播放...");  
					((Button) v).setText(R.string.button_pause);// 文字:继续-->暂停
				}
			}
			break;
		// 重播按钮
		case R.id.button_replay:
			if (mediaPlayer.isPlaying()) {
				textView.setText("音乐重新播放...");  
				mediaPlayer.seekTo(0);// 从开始位置开始播放音乐
			} else {
				if (filePath != null) {
					play(0);
				}
			}
			break;
		// 停止按钮
		case R.id.button_stop:
			if (mediaPlayer.isPlaying()) {
				textView.setText("音乐停止播放...");  
				mediaPlayer.stop();
			}
			break;
		}
	}

	/**
	 * 播放音乐
	 * @param playPosition 
	 */
	private void play(int playPosition) {
		try {
			mediaPlayer.reset();// 把各项参数恢复到初始状态
			/**
			 * 	通过MediaPlayer.setDataSource() 的方法,将URL或文件路径以字符串的方式传入.使用setDataSource ()方法时,要注意以下三点:
				1.构建完成的MediaPlayer 必须实现Null 对像的检查.
				2.必须实现接收IllegalArgumentException 与IOException 等异常,在很多情况下,你所用的文件当下并不存在.
				3.若使用URL 来播放在线媒体文件,该文件应该要能支持pragressive 下载.
			 */
			mediaPlayer.setDataSource(filePath);
			mediaPlayer.prepare();// 进行缓冲
			mediaPlayer.setOnPreparedListener(new MyPreparedListener(playPosition));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private final class MyPreparedListener implements
			android.media.MediaPlayer.OnPreparedListener {
		private int playPosition;
		public MyPreparedListener(int playPosition) {
			this.playPosition=playPosition;
		}

		@Override
		public void onPrepared(MediaPlayer mp) {
			mediaPlayer.start();// 开始播放
			if (playPosition>0) {
				mediaPlayer.seekTo(playPosition);
			}
		}

	}

}



Step 5:由于加入了监听电话的功能,所以要在AndroidManifest.xml中配置权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="cn.roco.mp3"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />
    
    <!-- 注意:这里要加入一个监听电话的权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>



Step 6: 运行效果如下,一首动听的Avril Lavigne - Complicated.mp3在播放...


  (1) (2)(3) (4)(5) 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值