• Android开发之Mediaplayer


     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 }
    复制代码

     

     效果展示:




  • 相关阅读:
    JS加强学习-BOM学习03
    JS加强学习-BOM学习02
    JS加强学习-BOM学习01
    JS加强学习-DOM学习总结
    JS加强学习-DOM学习05
    JS加强学习-DOM学习04
    JS加强学习-DOM学习03
    《雨霖铃》——柳永
    《青玉案·元夕》——辛弃疾
    《沁园春·雪》——毛 泽东
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4310387.html
Copyright © 2020-2023  润新知