博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于MediaPlayer的详细介绍
阅读量:4934 次
发布时间:2019-06-11

本文共 11411 字,大约阅读时间需要 38 分钟。

1)如何获得MediaPlayer实例:

可以使用直接new的方式:
MediaPlayer mp = new MediaPlayer();
也可以使用create的方式,如:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//这时就不用调用setDataSource了
2) 如何设置要播放的文件:
MediaPlayer要播放的文件主要包括3个来源:
a. 用户在应用中事先自带的resource资源
例如:MediaPlayer.create(this, R.raw.test);
b. 存储在SD卡或其他文件路径下的媒体文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 网络上的媒体文件
例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");
MediaPlayer的setDataSource一共四个方法:
setDataSource (String path) 
setDataSource (FileDescriptor fd) 
setDataSource (Context context, Uri uri) 
setDataSource (FileDescriptor fd, long offset, long length)
 
其中使用FileDescriptor时,需要将文件放到与res文件夹平级的assets文件夹里,然后使用:
AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());

来设置datasource

 

 

提供了常见的音频、视频的编码、解码机制。借助于多媒体类MediaPlayer的支持,开发人员可以很方便在在应用中播放音频、视频。本篇博客主要讲解在平台下如何播放一个音频文件。

  本篇博客主要内容如下:

  • MediaPlayer
  • MediaPlayer的音频源
  • 使用MediaPlayer播放音乐
  • MediaPlayer使用技巧
  • Demo--一个简单的MP3播放器

  

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.
1                 mediaPlayer = new MediaPlayer();
2.
2                 mediaPlayer.setDataSource(
"/sdcarc/a.mp3"
);
 

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

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

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

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

  如果访问网络流媒体资源,还需要设置访问网络的权限:

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

 

 

使用MediaPlayer播放音乐

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

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

  • void statr():开始或恢复播放。
  • 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)错误。

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

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

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

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

01.
1     @Override
02.
2     protected void onDestroy() {
03.
3         
if 
(mediaPlayer != null && mediaPlayer.isPlaying()) {
04.
4             mediaPlayer.stop();
05.
5             mediaPlayer.release();
06.
6             mediaPlayer = null;
07.
7         }
08.
8         super.onDestroy();
09.
9     }
 

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

01.
1                 // 设置循环播放
02.
2 //                mediaPlayer.setLooping(
true
);
03.
3                 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
04.
4                    
05.
5                     @Override
06.
6                     public void onCompletion(MediaPlayer mp) {
07.
7                         // 在播放完毕被回调
08.
8                         play();                       
09.
9                     }
10.
10                 });
 

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

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

 

 

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

  上面已经介绍了MediaPlayer播放一段音频文件的所有需要用到的内容。下面通过一个简单的Demo来演示如何使用MediaPlayer播放一个SD卡上的MP3文件。操作MediaPlayer应该放在Service中完成,这里为了简单,使用Activity直接操作MediaPlayer。代码注释里写的很清楚里,这里不再累述。

  执行这个示例需要在/sdcard/目录下存在xm.mp3的文件。  

001.
1 package cn.bgxt.mediaplayerdemo;
002.
2
003.
import 
java.io.File;
004.
import 
android.media.AudioManager;
005.
import 
android.media.MediaPlayer;
006.
import 
android.media.MediaPlayer.OnCompletionListener;
007.
import 
android.media.MediaPlayer.OnErrorListener;
008.
import 
android.media.MediaPlayer.OnPreparedListener;
009.
import 
android.os.Bundle;
010.
10 
import 
android.app.Activity;
011.
11 
import 
android.view.View;
012.
12 
import 
android.widget.Button;
013.
13 
import 
android.widget.EditText;
014.
14 
import 
android.widget.Toast;
015.
15
016.
16 public class MainActivity extends Activity {
017.
17     private EditText et_path;
018.
18     private Button btn_play, btn_pause, btn_replay, btn_stop;
019.
19     private MediaPlayer mediaPlayer;
020.
20
021.
21     @Override
022.
22     protected void onCreate(Bundle savedInstanceState) {
023.
23         super.onCreate(savedInstanceState);
024.
24         setContentView(R.layout.activity_main);
025.
25
026.
26         et_path = (EditText) findViewById(R.
id
.et_path);
027.
27         btn_play = (Button) findViewById(R.
id
.btn_play);
028.
28         btn_pause = (Button) findViewById(R.
id
.btn_pause);
029.
29         btn_replay = (Button) findViewById(R.
id
.btn_replay);
030.
30         btn_stop = (Button) findViewById(R.
id
.btn_stop);
031.
31
032.
32         btn_play.setOnClickListener(click);
033.
33         btn_pause.setOnClickListener(click);
034.
34         btn_replay.setOnClickListener(click);
035.
35         btn_stop.setOnClickListener(click);
036.
36     }
037.
37
038.
38     private View.OnClickListener click = new View.OnClickListener() {
039.
39
040.
40         @Override
041.
41         public void onClick(View 
v
) {
042.
42
043.
43             switch (
v
.getId()) {
044.
44             
case 
R.
id
.btn_play:
045.
45                 play();
046.
46                 
break
;
047.
47             
case 
R.
id
.btn_pause:
048.
48                 pause();
049.
49                 
break
;
050.
50             
case 
R.
id
.btn_replay:
051.
51                 replay();
052.
52                 
break
;
053.
53             
case 
R.
id
.btn_stop:
054.
54                 stop();
055.
55                 
break
;
056.
56             default:
057.
57                 
break
;
058.
58             }
059.
59         }
060.
60     };
061.
61     /**
062.
62      * 播放音乐
063.
63      */
064.
64     protected void play() {
065.
65         String path = et_path.getText().toString().trim();
066.
66         File 
file 
= new File(path);
067.
67         
if 
(
file
.exists() && 
file
.length() &
gt
; 0) {
068.
68             try {
069.
69                 mediaPlayer = new MediaPlayer();
070.
70                 // 设置指定的流媒体地址
071.
71                 mediaPlayer.setDataSource(path);
072.
72                 // 设置音频流的类型
073.
73                 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
074.
74
075.
75                 // 通过异步的方式装载媒体资源
076.
76                 mediaPlayer.prepareAsync();
077.
77                 mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
078.
78                     @Override
079.
79                     public void onPrepared(MediaPlayer mp) {
080.
80                         // 装载完毕 开始播放流媒体
081.
81                         mediaPlayer.start();
082.
82                         Toast.makeText(MainActivity.this, 
"开始播放"
, 0).show();
083.
83                         // 避免重复播放,把播放按钮设置为不可用
084.
84                         btn_play.setEnabled(
false
);
085.
85                     }
086.
86                 });
087.
87                 // 设置循环播放
088.
88                 // mediaPlayer.setLooping(
true
);
089.
89                 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
090.
90
091.
91                     @Override
092.
92                     public void onCompletion(MediaPlayer mp) {
093.
93                         // 在播放完毕被回调
094.
94                         btn_play.setEnabled(
true
);
095.
95                     }
096.
96                 });
097.
97
098.
98                 mediaPlayer.setOnErrorListener(new OnErrorListener() {
099.
99
100.
100                     @Override
101.
101                     public boolean onError(MediaPlayer mp, int what, int extra) {
102.
102                         // 如果发生错误,重新播放
103.
103                         replay();
104.
104                         
return 
false
;
105.
105                     }
106.
106                 });
107.
107             } catch (Exception e) {
108.
108                 e.printStackTrace();
109.
109                 Toast.makeText(this, 
"播放失败"
, 0).show();
110.
110             }
111.
111         } 
else 
{
112.
112             Toast.makeText(this, 
"文件不存在"
, 0).show();
113.
113         }
114.
114
115.
115     }
116.
116     /**
117.
117      * 暂停
118.
118      */
119.
119     protected void pause() {
120.
120         
if 
(btn_pause.getText().toString().trim().equals(
"继续"
)) {
121.
121             btn_pause.setText(
"暂停"
);
122.
122             mediaPlayer.start();
123.
123             Toast.makeText(this, 
"继续播放"
, 0).show();
124.
124             
return
;
125.
125         }
126.
126         
if 
(mediaPlayer != null && mediaPlayer.isPlaying()) {
127.
127             mediaPlayer.pause();
128.
128             btn_pause.setText(
"继续"
);
129.
129             Toast.makeText(this, 
"暂停播放"
, 0).show();
130.
130         }
131.
131
132.
132     }
133.
133    
134.
134     /**
135.
135      * 重新播放
136.
136      */
137.
137     protected void replay() {
138.
138         
if 
(mediaPlayer != null && mediaPlayer.isPlaying()) {
139.
139             mediaPlayer.seekTo(0);
140.
140             Toast.makeText(this, 
"重新播放"
, 0).show();
141.
141             btn_pause.setText(
"暂停"
);
142.
142             
return
;
143.
143         }       
144.
144         play();
145.
145     }
146.
146    
147.
147     /**
148.
148      * 停止播放
149.
149      */
150.
150     protected void stop() {
151.
151         
if 
(mediaPlayer != null && mediaPlayer.isPlaying()) {
152.
152             mediaPlayer.stop();
153.
153             mediaPlayer.release();
154.
154             mediaPlayer = null;
155.
155             btn_play.setEnabled(
true
);
156.
156             Toast.makeText(this, 
"停止播放"
, 0).show();
157.
157         }
158.
158
159.
159     }
160.
160
161.
161     @Override
162.
162     protected void onDestroy() {
163.
163         // 在activity结束的时候回收资源
164.
164         
if 
(mediaPlayer != null && mediaPlayer.isPlaying()) {
165.
165             mediaPlayer.stop();
166.
166             mediaPlayer.release();
167.
167             mediaPlayer = null;
168.
168         }
169.
169         super.onDestroy();
170.
170     }
171.
171 }

转载于:https://www.cnblogs.com/pastor/p/5077840.html

你可能感兴趣的文章
bzoj 4237稻草人
查看>>
在发送intent启动activity之前判断是否有activity接收
查看>>
html5特征检测
查看>>
js中几种实用的跨域方法原理详解
查看>>
打印图形
查看>>
《第一行代码》学习笔记7-活动Activity(5)
查看>>
ngx_http_core_module 模块
查看>>
两个常见的oracle索引
查看>>
一位有着工匠精神的博主写的关于IEnumerable接口的详细解析
查看>>
MySQL中特有的函数If函数
查看>>
安装Python3.6.2报错:zipimport.ZipImportError: can't decompress data; zlib not available
查看>>
【蓝桥杯】入门训练 Fibonacci数列
查看>>
实验十 指针2
查看>>
常见HTTP状态码
查看>>
vim 空格和换行的删除和替换
查看>>
ionic 入门学习
查看>>
[python]pickle和cPickle
查看>>
末日了,天是灰色的。
查看>>
Vuejs vm对象详解
查看>>
自定义RatingBar的一个问题(只显示显示一个星星)
查看>>