zoukankan      html  css  js  c++  java
  • 关于MediaPlayer的详细介绍

    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

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

      本篇博客主要内容如下:

    • 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(http://192.168.1.102: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 }
  • 相关阅读:
    [上海线下活动]IT俱乐部新春首期活动: 高级Windows调试
    清除www.fa899.com
    [新功能]总是只列出标题
    [功能改进]更多的列表数定制
    新增Skin使用排行榜
    华硕P5GDCV Deluxe主板更换RAID 1中的故障硬盘步骤
    [WebPart发布]网站链接WebPart
    [通知]19:3020:30进行服务器维护
    [小改进]个人Blog首页显示随笔摘要
    新增两款Skin(clover与Valentine)
  • 原文地址:https://www.cnblogs.com/pastor/p/5077840.html
Copyright © 2011-2022 走看看