分享

MediaPlayer详解

 杰出天下 2013-09-16

大家好我们今天研究的是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./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./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) 


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多