Android音频使用总结

来源:互联网 发布:多条update sql语句 编辑:程序博客网 时间:2024/06/05 11:41

本文对Android音频播放做简单总结。

一.基本概念

(一)Android媒体格式

     Android提供了对常用音频和视频格式的支持,它所支持的音频格式有MP3,3GP,OGG,和 WAVE(.ave)等,支持的视频格式有3GP和MPEG-4等,通过Android API提供的方法,可以实现音 频与视频的播放。
     播放SD卡中的一个音频文件 ,注意权限的添加:
Android.permission.READ_EXTERNAL_STORAGE

(二)播放音频文件,一般使用的是:MediaPlayer类或SoundPool类。

二.MediaPlayer的使用总结

Media Player可以使用静态方法创建也可以使用无参构造的方法来创建。

(一)静态方法创建MediaPlayer对象

使用create方法来绑定资源

1.用于从资源ID对应的资源文件中装载音频,并返回新创建的MediaPlayer对象

MediaPlayer player=MediaPlayer.create(this,R.raw.d);
这里的资源文件是放在res/raw目录下的

2.用于根据指定的URI来装载音频,并返回新创建的MediaPlayer对象

MediaPlayer player=MediaPlayer.create(this,Uri,pares(“http://www.music.baidu.com/sou nd/mylove.mp3”));

     但是,注意,这里的访问网络上的资源时,要在AndroidManifest.xml文件中授予该程序访问网络 的权限,具代码如下

(二)根据无参数的构造方法,创建MediaPlayer对象

用setDataSource()方法实现资源的绑定。
具体代码:

MediaPlayer player=new MediaPlayer(); player.setDataSource(“/sdcard/s.wav”); player.prepare();

使用构造方法创建的MediaPlayer必须预加载音频。才能去播放文件。

(三)MediaPlayer的常用方法

1.setDataSource() //设置 资源
2.start() throws IllegalStateException //开 始播放,如果没有预编译错过会报错
3.stop() //停 止播放
4.pause() //暂 停播放
5.prepare()//同步加载
6.prepareAsync()// 异步加载,完成后调用监听
7.isPlaying(); //本 地方法,判断播放状态
8.seekTo(int msec) //本地方法,跳转到时间点
9.int getDuration(); //本 地方法,获取音乐总长度
10.release() //释 放资源
11.reset() //重 置MediaPlayer
12.setLooping(boolean looping) //设 置循环
13.public native boolean isLooping(); //判 断循环状态
14.setVolume(float leftVolume, float rightVolume)
/ /设置音量,左声道和右声道
15.setVolume(float volume) //设 置音量

同步与异步的区别 同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步是指进程不需 要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统 会通知进程进行处理,这样可以提高执行的效率。

(四)MediaPlayer的几个监听方式

1. 异步加载完成时回调监听

public void setOnPreparedListener(OnPreparedListener listener)
异步监听,一般在异步预加载之前就要设置好。

2.音乐播放完毕后回调监听

public void setOnCompletionListener(OnCompletionListener listener)
一般用于设置播放完毕后,播放下一首还是循环播放

3.当跳转完成时的监听

public void setOnSeekCompleteListener(OnSeekCompleteListener listener)
一般用于监听进度突然改变的值的变化

三.SoundPool的使用总结

     由于MediaPlayer占用资源较高,且不支持同时播放多个音频,所有Android为我们提供了另一个播放音频的类SounePool.SoundPool也就是音频池,它可以同时播放多个短促的音频,而且占用的资源少,例如游戏中的多个音频同时播放。
Sound Pool的音频文件也是放在res/raw/文件夹下面
使用SoundPool播放音频的步骤如下:

(一)创建SoundPool对象

new SoundPool(int maxStreams,int streamType,int srcQuality)
     其中,maxStreams用来指定可以容纳多少个音频,streamType用来指定声音类型,可以通过 AudioManager类提供的常量进行指定,通常使用STREAM_MUSIC; srcQuality参数用于指定音频的品质,0为默认

(二)加载所要播放的音频,四种方式

1. Public int load(Context context,int resid,int priority)

用于通过指定的资源来加载音频

2.Public int load(String path,int priority)

用于通过音频文件的路径来加载音频

3.Public int load(AssetFileDescriptor afd,int priority)

用于从AssetFileDescriptor所对应的文件中加载音频

4. Public int load(FileDescriptor fd,long offset,long length,int priority )

用于加载FileDescriptor对象中,从offset开始,长度为length的音频

(三)控制播放音频

play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
6个参数的说明:
1)soundID 用于指定要播放的音频,该音频为通过load()方法返回的音频
2)leftVolume 用于指定左声道的音量,取值为0-1.0
3)rightVolume 用于指定左声道的音量,取值为0-1.0
4) Priority 用于指定播放音频的优先级,数值越大,优先级越高
5)Loop 用于设置循环次数0为不循环-1为循环
6)Rate 用于指定速率,1为正常,最小值为0.5 最高值为2

     上面就是Android音频使用的类和常用的方法,下面结合实际,做两个简单的示例。

四.使用MediaPlayer来控制文件的播放和停止

程序功能实现:
1.能播放固定的音频文件资源
2.能控制音频文件的暂停和停止,开始
3.能够使用进度拖动条来控制音频文件的播放
     对于其他的一些复杂功能,暂时没有去实现。
这里的使用的是使用的静态方法和无参的构造方法来控制音频文件,实际应用中只使用一种就可以了。
     本程序上面两个按钮和下面两个按钮不能混用,一次程序运行中只能使用静态或者无参的对象来控制音频文件,这里只为了对比功能才放到一起的。

(一)xml文件的设计

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.lwz.mediaplayer.MainActivity">    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center"        android:text="音频播放"        android:textSize="20sp" />    <SeekBar        android:id="@+id/main_sb"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/main_tv_pro"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="right"        android:text="00:00/00:00"        android:textSize="15sp" />    <Button        android:id="@+id/main_btn_start"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="start"        android:text="播放" />    <Button        android:id="@+id/main_btn_stop"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="stop"        android:text="停止" />    <View        android:layout_width="match_parent"        android:layout_height="1dp"        android:background="#f00" />    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text=" 动态使用音频对象" />    <Button        android:id="@+id/main_btn_start2"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="start2"        android:text="播放" />    <Button        android:id="@+id/main_btn_stop2"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="stop2"        android:text="停止" /></LinearLayout>

(二)java代码的设计

package com.lwz.mediaplayer;import android.app.Activity;import android.media.MediaPlayer;import android.os.Bundle;import android.os.Environment;/*** * 音频文件的使用 * 静态方法:播放的是程序本身的音频文件在/src/raw/文件夹下 * 动态方法:播放的是存储器的音频文件 */public class MainActivity extends Activity implements SeekBar.OnSeekBarChangeListener {    //定义2个音频播放的对象    MediaPlayer mediaPlayer;    MediaPlayer mediaPlayer2;    //定义布局内的按钮控件    Button start;    Button stop;    Button start2;    Button stop2;    SeekBar seekBar;    TextView tv_time;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //实例化布局内的控件        start = (Button) findViewById(R.id.main_btn_start);        stop = (Button) findViewById(R.id.main_btn_stop);        start2 = (Button) findViewById(R.id.main_btn_start2);        stop2 = (Button) findViewById(R.id.main_btn_stop2);        seekBar = (SeekBar) findViewById(R.id.main_sb);        tv_time = (TextView) findViewById(R.id.main_tv_pro);        //设置停止按钮点无效        stop.setEnabled(false);        stop2.setEnabled(false);        //给SeekBar设置监听事件        seekBar.setOnSeekBarChangeListener(this);    }    public void start(View v) {        if (mediaPlayer == null) {            //如果音频文件对象是空的就实例化数据            mediaPlayer = MediaPlayer.create(this, R.raw.arcs);            //设置可以点击停止            stop.setEnabled(true);        }        //如果还没有开始播放,就播放音频,显示“暂停”        if (!mediaPlayer.isPlaying()) {            mediaPlayer.start();            start.setText("暂停");            //开始计算            startTime();            //设置进度条的最大值            seekBar.setMax(mediaPlayer.getDuration() / 1000);            //设置一直循环            mediaPlayer.setLooping(true);        } else {            //如果正在显示“暂停”时,单击暂停,就暂停音频,显示“播放”            mediaPlayer.pause();            start.setText("播放");            //取消定时器            timer.cancel();        }    }    public void start2(View v) {        if (mediaPlayer2 == null) {            //如果音频文件对象是空的就实例化数据            //动态使用音频对象和静态使用使用区别的,这里直接new出来            mediaPlayer2 = new MediaPlayer();            try {                //给音频对象设置资源地址                mediaPlayer2.setDataSource(Environment.getExternalStorageDirectory().getAbsolutePath() + "/laolang.mp3");                //这里要预加载                mediaPlayer2.prepare();            } catch (IOException e) {                e.printStackTrace();            }            //设置可以点击停止            stop2.setEnabled(true);        }        //如果还没有开始播放,就播放音频,显示“暂停”        if (!mediaPlayer2.isPlaying()) {            mediaPlayer2.start();            start2.setText("暂停");            //开始计算            startTime();            //设置进度条的最大值            seekBar.setMax(mediaPlayer2.getDuration() / 1000);            //设置一直循环            mediaPlayer2.setLooping(true);        } else {            //如果正在显示“暂停”时,单击暂停,就暂停音频,显示“播放”            mediaPlayer2.pause();            start2.setText("播放");            //取消定时器            timer.cancel();        }    }    /**     * 时间开始跑     * 这里设置一个Timer对象来控制时间     */    Timer timer;    //转换时间的一个对象    SimpleDateFormat format = new SimpleDateFormat("mm:ss");    private void startTime() {        timer = new Timer();        //一秒之后每秒执行一次的任务        timer.schedule(new TimerTask() {            @Override            public void run() {                //这里要在主线程执行                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        //进度条每次加一                        seekBar.setProgress(seekBar.getProgress() + 1);                        //获取当前播放的时间,单位毫秒秒                        int time = seekBar.getProgress() * 1000;                        //把显示进度的文字显示到屏幕上                        if(mediaPlayer2!=null)                        tv_time.setText(format.format(new Date(time)) + "/" + format.format(new Date(mediaPlayer2.getDuration())));                        if(mediaPlayer!=null)                        tv_time.setText(format.format(new Date(time)) + "/" + format.format(new Date(mediaPlayer.getDuration())));                        //结束后重新开始,进度条                        if (seekBar.getProgress() == seekBar.getMax()) {                            seekBar.setProgress(0);                        }                    }                });            }        }, 1000, 1000);    }    public void stop(View v) {        //这里是停止不是暂停        recyle();    }    public void stop2(View v) {        //这里是停止不是暂停        recyle2();    }    /**     * 彻底释放资源     */    public void recyle() {        //判断非空才需做处理        if (mediaPlayer != null) {            //保证音频停止            if (mediaPlayer.isPlaying()) {                mediaPlayer.stop();            }            //回收资源            mediaPlayer.release();            //设置对象为空            mediaPlayer = null;            //设置显示文本为播放            start.setText("播放");            //设置禁止点击"停止"            stop.setEnabled(false);        }        //取消时间计数器        timer.cancel();        //设置进度条的位置为开始的地方        seekBar.setProgress(0);    }    /**     * 彻底释放资源     */    public void recyle2() {        //判断非空才需做处理        if (mediaPlayer2 != null) {            //保证音频停止            if (mediaPlayer2.isPlaying()) {                mediaPlayer2.stop();            }            //回收资源            mediaPlayer2.release();            //设置对象为空            mediaPlayer2 = null;            //设置显示文本为播放            start2.setText("播放");            //设置禁止点击"停止"            stop2.setEnabled(false);        }        //取消时间计数器        timer.cancel();        //设置进度条的位置为开始的地方        seekBar.setProgress(0);    }    @Override    protected void onDestroy() {        //页面关闭前先彻底释放音频的资源        recyle();        recyle2();        super.onDestroy();    }    //定义一个布尔值判断是否是用户的操作的进度条    boolean fromUser;    //当进度条发送生改变时回调    @Override    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {        this.fromUser = fromUser;    }    //进度条操作开始时回调    @Override    public void onStartTrackingTouch(SeekBar seekar) {        fromUser = false;    }    //进度条操作停止时回调    @Override    public void onStopTrackingTouch(SeekBar seekBar) {        //如果是用户拖动的进度条才做对应的时间跳转        if (fromUser) {            //把音频播放时间设置到拖动的位置            int time = seekBar.getProgress() * 1000;            if (mediaPlayer != null) {                mediaPlayer.seekTo(time);            }        }    }}

程序运行前要保证资源文件的存在;
这里音频文件的停止和退出页面一定要释放资源。
程序运行后的效果:

是1
点击播放后效果:

播放
播放时点击暂停,就停止音频播放,如图所示:
停止
上面的动态使用音频对象功能也是一样的。
这里就可以实现对音频文件的基本控制了。

五.SoundPool播放音频的简单示例

     本示例功能比较简单,根据五种小音频文件,对应的设置五个按钮来触发播放,程序中可以同时播放多个音频,比如上一个音频文件没有播放完,下一个音频文件也可以播放。

(一)xml布局文件

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="play"        android:text="play" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="play1"        android:text="play1" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="play2"        android:text="play2" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="play3"        android:text="play3" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:onClick="play4"        android:text="play4" /></LinearLayout>

(二)java代码文件

package com.lwz.soundpool;import android.media.AudioManager;import android.media.SoundPool;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import java.util.HashMap;/** * 使用SoundPool播放音频,可以同时播放多个音频 * 但是主要是播放时间比较短的音频 * 它的文件资源也是一般放在本地中 */public class MainActivity extends AppCompatActivity {    SoundPool soundPool;    //创建一个集合存放音频数据    HashMap<Integer, Integer> map = new HashMap<>();    /*    创建SoundPool对象    1. SoundPool(int maxStreams,int streamType,int srcQuality)    2. //其中,maxStreams用来指定可以容纳多少个音频,streamType用来指定声音类型,可以通过    AudioManager类提供的常量进行指定,通常使用STREAM_MUSIC; srcQuality参数用于指定    音频的品质,0为默认    * */    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //创建音频对象        soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);        //给集合设置数据        map.put(1, soundPool.load(this, R.raw.chimes, 100));        map.put(2, soundPool.load(this, R.raw.ding, 100));        map.put(3, soundPool.load(this, R.raw.enter, 100));        map.put(4, soundPool.load(this, R.raw.notify, 100));        map.put(5, soundPool.load(this, R.raw.ringout, 100));    }    /*    * play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)    2. 参数说明:    3. 参数 描述    4. soundID 用于指定要播放的音频,该音频为通过load()方法返回的音频    5. leftVolume 用于指定左声道的音量,取值为0-1.0    6. rightVolume 用于指定左声道的音量,取值为0-1.0    7. priority 用于指定播放音频的优先级,数值越大,优先级越高    8. loop 用于设置循环次数0为不循环-1为循环    9. rate 用于指定速率,1为正常,最小值为0.5 最高值为2    * */    public void play(View v) {        soundPool.play(map.get(1), 1, 1, 100, 2, 1);    }    public void play1(View v) {        soundPool.play(map.get(2), 1, 1, 100, 2, 1);    }    public void play2(View v) {        soundPool.play(map.get(3), 1, 1, 100, 2, 1);    }    public void play3(View v) {        soundPool.play(map.get(4), 1, 1, 100, 2, 1);    }    public void play4(View v) {        soundPool.play(map.get(5), 1, 1, 100, 2, 1);    }    @Override    protected void onDestroy() {        super.onDestroy();        soundPool.release();    }}

程序运行后的结果:
声音
这里没有办法展示声音效果!

     对比这两个音频控制文件:
     MediaPlayer是可以播放长时间的音频文件,Sound Pool是用来播放短时间的音频文件的;
Media Player和SoundPool控制的音频文件都可以放在资源文件夹res/raw/下面,也可以使用存储器中的音频资源文件,但是SoundPool控制的文件一般比较下,放在/raw目录中即可。

4 0