Android提供了常见的音频、视频的编码、解码机制。借助于多媒体类MediaPlayer的支持,开发者能够非常方便在在应用中播放音频、视频。本篇博客主要解说在Android平台下怎样播放一个音频文件。

  本篇博客主要内容例如以下:

MediaPlayer

  上面提到过,Android下对于音频、视频的支持均须要使用到MediaPlayer,它主要用来控制Android下播放文件或流的类。MediaPlayer处于Android多媒体包下"android.media.MediaPlayer",仅有一个无參的构造函数,尽管仅为我们提供了一个无參的构造函数,为了方便我们初始化,还为我们提供了几个静态的create()方法用于完毕MediaPlayer初始化的工作。

  • static MediaPlayer create(Context context,int resid):通过音频资源的Id来创建一个MediaPlayer实例。
  • static MediaPlayer create(Context context,Uri uri):通过一个音频资源的Uri地址来创建一个MediaPlayer实例。

  MediaPlayer除了通过上面两个create()方法在初始化的时候指定媒体资源,还能够通过MediaPlayer.setDataSource()方法为初始化后的MediaPlayer设置媒体资源,setDataSource()具有多个重载函数,适用于不同的媒体资源来源,下面解说几个经常使用的,其它的能够查阅官方文档。

  • void setDataSource(String path):通过一个媒体资源的地址指定MediaPlayer的数据源,这里的path能够是一个本地路径,也能够是网络路径。
  • void setDataSource(Context context,Uri uri):通过一个Uri指定MediaPlayer的数据源,这里的Uri能够是网络路径或这一个内容提供者的Uri。
  • void setDataSource(FileDescriptor fd):通过一个FileDescriptor指定一个MediaPlayer的数据源。

MediaPlayer的音频源

  通过上面介绍的初始化MediaPlayer的播放时媒体数据源的方法能够看出,MediaPlayer支持的数据源有:本地文件、内部的Uri(内容提供者)、外部Uri。

  如,设置一个本地SD卡的资源:

1                 mediaPlayer = new MediaPlayer();
2 mediaPlayer.setDataSource("/sdcarc/a.mp3");

  注意读内存卡,还须要设定訪问内存卡的权限:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

  如,设置一个外部uri的网络流媒体资源:

1                 mediaPlayer = new MediaPlayer();
2 mediaPlayer.setDataSource(http://192.168.1.102:1231/music/a.mp3);

  假设訪问网络流媒体资源,还须要设置訪问网络的权限:

    <uses-permission android:name="android.permission.INTERNET"/>

使用MediaPlayer播放音乐

  MediaPlayer事实上是一个封装的非常好的音频、视频流媒体操作类,假设查看其源代码,会发现其内部是调用的native方法,所以它事实上是有C++实现的。

  既然是一个流媒体操作类,那么必定涉及到,播放、暂停、停止等操作,实际上MediaPlayer也为我们提供了对应的方法来直接操作流媒体。

  • void start():開始或恢复播放。
  • void stop():停止播放。
  • void pause():暂停播放。  

  通过上面三个方法,仅仅要设定好流媒体数据源,就可以在应用中播放流媒体资源,为了更好的操作流媒体,MediaPlayer还为我们提供了一些其它的方法,这里列出一些经常使用的,具体内容參阅官方文档。

  • int getDuration():获取流媒体的总播放时长,单位是毫秒。
  • int getCurrentPosition():获取当前流媒体的播放的位置,单位是毫秒。
  • void seekTo(int msec):设置当前MediaPlayer的播放位置,单位是毫秒。
  • void setLooping(boolean looping):设置是否循环播放。
  • boolean isLooping():推断是否循环播放。
  • boolean  isPlaying():推断是否正在播放。
  • void prepare():同步的方式装载流媒体文件。
  • void prepareAsync():异步的方式装载流媒体文件。
  • void release ():回收流媒体资源。
  • void setAudioStreamType(int streamtype):设置播放流媒体类型。
  • void setWakeMode(Context context, int mode):设置CPU唤醒的状态。
  • setNextMediaPlayer(MediaPlayer next):设置当前流媒体播放完成,下一个播放的MediaPlayer。

  大部分方法的看方法名就能够理解,可是有几个方法须要单独说明一下。

  在使用MediaPlayer播放一段流媒体的时候,须要使用prepare()或prepareAsync()方法把流媒体装载进MediaPlayer,才干够调用start()方法播放流媒体。                 

  setAudioStreamType()方法用于指定播放流媒体的类型,它传递的是一个int类型的数据,均以常量定义在AudioManager类中, 一般我们播放音频文件,设置为AudioManager.STREAM_MUSIC就可以。

  

  除了上面介绍的一些方法外,MediaPlayer还提供了一些事件的回调函数,这里介绍几个经常使用的:

  • setOnCompletionListener(MediaPlayer.OnCompletionListener listener):当流媒体播放完成的时候回调。
  • setOnErrorListener(MediaPlayer.OnErrorListener listener):当播放中错误发生的时候回调。
  • setOnPreparedListener(MediaPlayer.OnPreparedListener listener):当装载流媒体完成的时候回调。
  • setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):当使用seekTo()设置播放位置的时候回调。

MediaPlayer使用技巧

  在使用MediaPlayer的使用过程中,有个小技巧须要说明一下:

  1、在使用start()播放流媒体之前,须要装载流媒体资源。这里最好使用prepareAsync()用异步的方式装载流媒体资源。由于流媒体资源的装载是会消耗系统资源的,在一些硬件不理想的设备上,假设使用prepare()同步的方式装载资源,可能会造成UI界面的卡顿,这是很影响用于体验的。由于推荐使用异步装载的方式,为了避免还没有装载完毕就调用start()而报错的问题,须要绑定MediaPlayer.setOnPreparedListener()事件,它将在异步装载完毕之后回调。异步装载另一个优点就是避免装载超时引发ANR((Application
Not Responding)错误。

 1                 mediaPlayer = new MediaPlayer();
2 mediaPlayer.setDataSource(path);
3 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
4
5 // 通过异步的方式装载媒体资源
6 mediaPlayer.prepareAsync();
7 mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
8 @Override
9 public void onPrepared(MediaPlayer mp) {
10 // 装载完成回调
11 mediaPlayer.start();
12 }
13 });

  2、使用完MediaPlayer须要回收资源。MediaPlayer是非常消耗系统资源的,所以在使用完MediaPlayer,不要等待系统自己主动回收,最好是主动回收资源。

1         if (mediaPlayer != null && mediaPlayer.isPlaying()) {
2 mediaPlayer.stop();
3 mediaPlayer.release();
4 mediaPlayer = null;
5 }

  3、使用MediaPlayer最好使用一个Service来使用,而且在Service的onDestory()方法中回收MediaPlayer资源,实际上,就算是直接使用Activity承载MediaPlayer,也最好在销毁的时候推断一下MediaPlayer是否被回收,假设未被回收,回收其资源,由于底层调用的native方法,假设不销毁还是会在底层继续播放,而承载的组件已经被销毁了,这个时候就无法获取到这个MediaPlayer进而控制它。

1     @Override
2 protected void onDestroy() {
3 if (mediaPlayer != null && mediaPlayer.isPlaying()) {
4 mediaPlayer.stop();
5 mediaPlayer.release();
6 mediaPlayer = null;
7 }
8 super.onDestroy();
9 }

  4、对于单曲循环之类的操作,除了能够使用setLooping()方法进行设置之外,还能够为MediaPlayer注冊回调函数,MediaPlayer.setOnCompletionListener(),它会在MediaPlayer播放完成被回调。

 1                 // 设置循环播放
2 // mediaPlayer.setLooping(true);
3 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4
5 @Override
6 public void onCompletion(MediaPlayer mp) {
7 // 在播放完成被回调
8 play();
9 }
10 });

  5、由于MediaPlayer一直操作的是一个流媒体,所以无可避免的可能一段流媒体资源,前半段能够正常播放,而中间一段由于解析或者源文件错误等问题,造成中间一段无法播放问题,须要我们处理这个错误,否则会影响Ux(用户体验)。能够为MediaPlayer注冊回调函数setOnErrorListener()来设置出错之后的解决的方法,一般又一次播放或者播放下一个流媒体就可以。  

1                 mediaPlayer.setOnErrorListener(new OnErrorListener() {
2
3 @Override
4 public boolean onError(MediaPlayer mp, int what, int extra) {
5 play();
6 return false;
7 }
8 });

Demo--一个简单的MP3播放器

  上面已经介绍了MediaPlayer播放一段音频文件的全部须要用到的内容。以下通过一个简单的Demo来演示怎样使用MediaPlayer播放一个SD卡上的MP3文件。操作MediaPlayer应该放在Service中完毕,这里为了简单,使用Activity直接操作MediaPlayer。代码凝视里写的非常清楚里,这里不再累述。

  运行这个演示样例须要在/sdcard/文件夹下存在xm.mp3的文件。  

  1 package cn.bgxt.mediaplayerdemo;
2
3 import java.io.File;
4 import android.media.AudioManager;
5 import android.media.MediaPlayer;
6 import android.media.MediaPlayer.OnCompletionListener;
7 import android.media.MediaPlayer.OnErrorListener;
8 import android.media.MediaPlayer.OnPreparedListener;
9 import android.os.Bundle;
10 import android.app.Activity;
11 import android.view.View;
12 import android.widget.Button;
13 import android.widget.EditText;
14 import android.widget.Toast;
15
16 public class MainActivity extends Activity {
17 private EditText et_path;
18 private Button btn_play, btn_pause, btn_replay, btn_stop;
19 private MediaPlayer mediaPlayer;
20
21 @Override
22 protected void onCreate(Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState);
24 setContentView(R.layout.activity_main);
25
26 et_path = (EditText) findViewById(R.id.et_path);
27 btn_play = (Button) findViewById(R.id.btn_play);
28 btn_pause = (Button) findViewById(R.id.btn_pause);
29 btn_replay = (Button) findViewById(R.id.btn_replay);
30 btn_stop = (Button) findViewById(R.id.btn_stop);
31
32 btn_play.setOnClickListener(click);
33 btn_pause.setOnClickListener(click);
34 btn_replay.setOnClickListener(click);
35 btn_stop.setOnClickListener(click);
36 }
37
38 private View.OnClickListener click = new View.OnClickListener() {
39
40 @Override
41 public void onClick(View v) {
42
43 switch (v.getId()) {
44 case R.id.btn_play:
45 play();
46 break;
47 case R.id.btn_pause:
48 pause();
49 break;
50 case R.id.btn_replay:
51 replay();
52 break;
53 case R.id.btn_stop:
54 stop();
55 break;
56 default:
57 break;
58 }
59 }
60 };
61 /**
62 * 播放音乐
63 */
64 protected void play() {
65 String path = et_path.getText().toString().trim();
66 File file = new File(path);
67 if (file.exists() && file.length() > 0) {
68 try {
69 mediaPlayer = new MediaPlayer();
70 // 设置指定的流媒体地址
71 mediaPlayer.setDataSource(path);
72 // 设置音频流的类型
73 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
74
75 // 通过异步的方式装载媒体资源
76 mediaPlayer.prepareAsync();
77 mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
78 @Override
79 public void onPrepared(MediaPlayer mp) {
80 // 装载完成 開始播放流媒体
81 mediaPlayer.start();
82 Toast.makeText(MainActivity.this, "開始播放", 0).show();
83 // 避免反复播放,把播放button设置为不可用
84 btn_play.setEnabled(false);
85 }
86 });
87 // 设置循环播放
88 // mediaPlayer.setLooping(true);
89 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
90
91 @Override
92 public void onCompletion(MediaPlayer mp) {
93 // 在播放完成被回调
94 btn_play.setEnabled(true);
95 }
96 });
97
98 mediaPlayer.setOnErrorListener(new OnErrorListener() {
99
100 @Override
101 public boolean onError(MediaPlayer mp, int what, int extra) {
102 // 假设错误发生,又一次播放
103 replay();
104 return false;
105 }
106 });
107 } catch (Exception e) {
108 e.printStackTrace();
109 Toast.makeText(this, "播放失败", 0).show();
110 }
111 } else {
112 Toast.makeText(this, "文件不存在", 0).show();
113 }
114
115 }
116 /**
117 * 暂停
118 */
119 protected void pause() {
120 if (btn_pause.getText().toString().trim().equals("继续")) {
121 btn_pause.setText("暂停");
122 mediaPlayer.start();
123 Toast.makeText(this, "继续播放", 0).show();
124 return;
125 }
126 if (mediaPlayer != null && mediaPlayer.isPlaying()) {
127 mediaPlayer.pause();
128 btn_pause.setText("继续");
129 Toast.makeText(this, "暂停播放", 0).show();
130 }
131
132 }
133
134 /**
135 * 又一次播放
136 */
137 protected void replay() {
138 if (mediaPlayer != null && mediaPlayer.isPlaying()) {
139 mediaPlayer.seekTo(0);
140 Toast.makeText(this, "又一次播放", 0).show();
141 btn_pause.setText("暂停");
142 return;
143 }
144 play();
145 }
146
147 /**
148 * 停止播放
149 */
150 protected void stop() {
151 if (mediaPlayer != null && mediaPlayer.isPlaying()) {
152 mediaPlayer.stop();
153 mediaPlayer.release();
154 mediaPlayer = null;
155 btn_play.setEnabled(true);
156 Toast.makeText(this, "停止播放", 0).show();
157 }
158
159 }
160
161 @Override
162 protected void onDestroy() {
163 // 在activity结束的时候回收资源
164 if (mediaPlayer != null && mediaPlayer.isPlaying()) {
165 mediaPlayer.stop();
166 mediaPlayer.release();
167 mediaPlayer = null;
168 }
169 super.onDestroy();
170 }
171 }

 效果展示:

Android开发之Mediaplayer的更多相关文章

  1. Android开发之MediaPlayer和SurfaceView组成视频播放器

    SurfaceView 使用双缓冲技术 是个重量级的组件 只要不可见,就不会创建,可见时,才会创建 只要不可见,就会销毁 SurfaceView一旦不可见,就会被销毁,一旦可见,就会被创建,销毁时停止 ...

  2. android开发之MediaPlayer+Service MP3播放器

    import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Lis ...

  3. Android开发之MediaPlayer类

    官网关于MediaPlayer类的使用简介:

  4. [置顶] Android开发之MediaPlayerService服务详解(一)

    前面一节我们分析了Binder通信相关的两个重要类:ProcessState 和 IPCThreadState.ProcessState负责打开Binder 驱动,每个进程只有一个.而 IPCThre ...

  5. Android开发之MdiaPlayer详解

    Android开发之MdiaPlayer详解 MediaPlayer类可用于控制音频/视频文件或流的播放,我曾在<Android开发之基于Service的音乐播放器>一文中介绍过它的使用. ...

  6. Android开发之Java集合类性能分析

    对于Android开发者来说深入了解Java的集合类很有必要主要是从Collection和Map接口衍生出来的,目前主要提供了List.Set和 Map这三大类的集合,今天Android吧(ard8. ...

  7. Android开发之InstanceState详解

    Android开发之InstanceState详解   本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...

  8. Android开发之Git配置

    Android开发之Git配置 1.首先git配置: 输入命令: git config --global user.name "xxx.xx" git config --globa ...

  9. 【Android UI】Android开发之View的几种布局方式及实践

    引言 通过前面两篇: Android 开发之旅:又见Hello World! Android 开发之旅:深入分析布局文件&又是“Hello World!” 我们对Android应用程序运行原理 ...

随机推荐

  1. MailTest

    GridBagLayout把一个界面分为m行n列的网格 GridBagConstraints的一个实例:gridx = 2; // X2,表示组件位于第2列gridy = 0; // Y0,表示组件位 ...

  2. Visual Studio Team Services使用教程--Readers tfs组成员添加

  3. LNK快捷方式漏洞利用方式 exp制作教程

    前言windows的shell32在处理控制面板程序的快捷方式文件时,存在一个漏洞,能够载入硬盘上的随意DLL文件,就可以运行随意代码. 漏洞文件的生成到“控制面板”以下,右键点“显示”,点“创建快捷 ...

  4. 【POJ3612】【USACO 2007 Nov Gold】 1.Telephone Wire 动态调节

    意甲冠军: 一些树高给出.行一种操作:把某棵树增高h,花费为h*h. 操作完毕后连线,两棵树间花费为高度差*定值c. 求两种花费加和最小值. 题解: 跟NOIP2014 D1T3非常像. 暴力动规是O ...

  5. js调用跨域

    web aapi 初体验 解决js调用跨域问题   跨域界定 常见跨域: 同IP不同端口: http:IP:8001/api/user     http:IP:8002/api/user 不同IP不同 ...

  6. 走向DBA[MSSQL篇] 积跬步行千里

    原文:走向DBA[MSSQL篇] 积跬步行千里 不知道大家对SQL系列的感不感兴趣 先在这里探个路 本文针对的读者为SQL菜鸟 欢迎大牛驳论或者补充 既然是探路篇 就先说下数据过滤中的偏门匹配 希望能 ...

  7. 用Maven打包成EAR远程部署JBoss(二)——部署到远程JBoss

    用Maven打包成EAR远程部署JBoss(一)讲了如何使用Maven打包,可是在文章的最后也留下了一个问题,那就是如何将包部署到远程的JBoss中呢?近期在对之前的学习进行总结,发现少了这样一篇重要 ...

  8. c# Ftp下载程序源代码解析

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  9. 如何使用滑动菜单SlidingMenu?

    左側滑: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVuaHVhaG91c2U=/font/5a6L5L2T/fontsize/400/fill/I ...

  10. 如何基于对话框的project基于改变BCG的

    一,stdafx.h 增加在下面的例子.BCGCBProInc.h间接介绍lib.   #include <BCGCBProInc.h> // BCGControlBar Pro #if ...