我的Android进阶之旅------>Android MediaPlayer播放mp3的实例--简易mp3播放器

简介: 大家好我们今天研究的是Android中很重要也最为复杂的媒体播放器---MediaPlayer. Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用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) (6)



如果想加入进度条等功能  可以参考 Android MediaPlayer播放网络音频的实例--网络mp3播放器    这篇文章




==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/ouyang_peng

==================================================================================================


相关文章
|
1月前
|
Shell Android开发 数据安全/隐私保护
安卓逆向 -- Frida环境搭建(HOOK实例)
安卓逆向 -- Frida环境搭建(HOOK实例)
15 0
|
2月前
|
XML 存储 Java
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
22 0
|
2月前
|
XML Java Android开发
Android Studio App开发中使用录音机、MediaRecorder录制音频和MediaPlayer播放音频讲解及实战(附源码)
Android Studio App开发中使用录音机、MediaRecorder录制音频和MediaPlayer播放音频讲解及实战(附源码)
32 0
|
2月前
|
Java 关系型数据库 数据库
Android App连接真机步骤与APP的开发语言和工程结构讲解以及运行实例(超详细必看)
Android App连接真机步骤与APP的开发语言和工程结构讲解以及运行实例(超详细必看)
22 0
|
4月前
|
Shell Android开发 数据安全/隐私保护
安卓逆向 -- Frida环境搭建(HOOK实例)
安卓逆向 -- Frida环境搭建(HOOK实例)
50 0
|
5月前
|
编解码 网络协议 Android开发
Android平台RTMP|RTSP直播播放器功能进阶探讨
很多开发者在跟我聊天的时候,经常问我,为什么一个RTMP或RTSP播放器,你们需要设计那么多的接口,真的有必要吗?带着这样的疑惑,我们今天聊聊Android平台RTMP、RTSP播放器常规功能,如软硬解码设置、实时音量调节、实时快照、实时录像、视频view翻转和旋转、画面填充模式设定、解码后YUV、RGB数据回调等:
|
5月前
|
编解码 Android开发 数据安全/隐私保护
Android平台外部编码数据(H264/H265/AAC/PCMA/PCMU)实时预览播放技术实现
好多开发者可能疑惑,外部数据实时预览播放,到底有什么用? 是的,一般场景是用不到的,我们在开发这块前几年已经开发了非常稳定的RTMP、RTSP直播播放模块,不过也遇到这样的场景,部分设备输出编码后(视频:H.264/H.265,音频:AAC/PCMA/PCMU)的数据,比如无人机或部分智能硬件设备,回调出来的H.264/H.265数据,除了想转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至对数据做二次处理(视频分析、实时水印字符叠加等,然后二次编码),基于这样的场景诉求,我们开发了Android平台外部编码数据实时预览播放模块。
|
5月前
|
编解码 Android开发 数据安全/隐私保护
Android平台如何实现外部编码后(H.264/H.265)数据实时预览播放
我们在对接开发者的时候,遇到这样的诉求:除了正常的RTMP、RTSP直播播放外,有些硬件设备输出编码后(H.264/H.265)的数据,比如无人机或类似硬件产品,回调出来的H.264/H.265数据,除了正常转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至重新对数据做二次处理,基于这样的场景诉求,我们开发了外部编码后数据实时预览播放模块。
|
5月前
|
前端开发 Android开发 开发者
Android平台RTSP、RTMP播放端如何实现YUV或ARGB数据按设定角度旋转
做音视频RTSP或RTMP直播播放器的时候,不免会遇到这样的诉求,实时播放或快照的时候,由于前端摄像头安装角度不一定是正向,导致播放或快照的时候,视频view显示的画面是呈90° 180°甚至270°旋转的。
114 0
|
5月前
|
Android开发 开发者
Android国标接入端如何播放GB28181平台端语音广播数据
GB28181语音广播这块,我们依据GB/T28181-2016针对流程和实例代码,做过详细的描述,本次主要是探讨下,广播数据过来后,如何处理。

相关产品

  • 云迁移中心