Android-音频播放(一)
最近学习了关于Android 的音频播放,以及系统中各应用之间对于音频播放的资源竞争处理。如何处理应用处于播放的状态下,其他的音频如何影响当前的状态。
例如:当手机播放一个音乐,同时来了一个电话,这时音乐停止,当通话结束时再继续播放。
![](https://img.haomeiwen.com/i2556431/32585fe8b96ddf0f.jpg)
如何创建一个播放音频
注意:Media Player 只介绍最基础的,其他的方法后期遇到在进行详解。
Media Player 类:媒体播放器类可用于控制播放的音频/视频文件和流。
![](https://img.haomeiwen.com/i2556431/e04989851ff4c5f7.gif)
创建一个音频的语法:
MediaPlayer mMediaPlayer = MediaPlayer.create(Context context, int resid);
第一个参数:播放的位置
第二个参数:音频的资源ID(一般方法哦 raw 文件夹中)
其中的方法我们只介绍常用的,以后遇到在进行总结归纳
//播放开始后暂停,再播放从上次停止的位置继续
start()进行播放
pause()暂停
//如果括号为0,音频回到最初的位置
seekTo() 指定的时间位置
reset()重置
//停止后 只有先prepare()才能 start()
stop()停止
prepare()准备
//当播放完后需要释放资源
release()释放资源
上述其他方法可以查看生命周期图
应用播放机制
要想播放音频,先要获取 Audio Focus,可以理解为只有获取到音频焦点的才可以播放,虽然 Android 2.2 之后添加了 Audio Focus,来处理系统之间音频的混乱。如果有程序在它失去AudioFocus的时候仍然在使用Audio,AudioFocus拿它也没办法,用户可能安装没遵守这种机制的程序,或者版本太老还没引入这种机制的程序,这最终会导致很差的用户体验。
- 如何获取 Audio Focus?
利用 AudioManager 来管理AudioFocus,先要实例化AudioManager
AudioManager mAudioManager=(AudioManager)getSystemService(this.AUDIO_SERVICE);
mAudioManager提供两个方法 :
**requestAudioFocus 获取焦点 **
int requestAudioFocus (AudioManager.OnAudioFocusChangeListener, int streamType, int durationHint);
参数:
- 焦点状态改变监听器
- 输入流类型
- STREAM_MUSIC 一般的音频其他的可以查看[官方文档](http://developer.android.youdaxue.com/reference/android/media/AudioManager.html#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int))
- 持续时间
- AUDIOFOCUS_GAIN_TRANSIENT 临时获取焦点,短时间释放
- AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 临时获取焦点,前焦点保持播放,其他降低音量
- AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE 介于上两个参数之间,不能破坏像通知,语音备忘,语言识别;
- AUDIOFOCUS_GAIN未知的时间播放歌曲或视频
请求焦点会有两个结果
1 AUDIOFOCUS_REQUEST_GRANTED 请求焦点成功
2 AUDIOFICUS_REQUEST_FAILED 请求焦点失败
**abandonAudioFocus 释放焦点 **
int abandonAudioFocus (AudioManager.OnAudioFocusChangeListener)
焦点状态改变监听器
通过一个 onAudioFocusChangeLiestener 方法回调来获得 Audiofocus 发生更改 后 的通知
监听设备更改 以便做出响应 onAudioFocusChangeLiestener 是一种接口 包含一个必须实施的onAudioFocusChange 抽象类(如果获得焦点 应该做什么,失去后应该做什么
onAudioFocusChange:
四个参数:
不懂的可以点看连接详细理解。
实战演练
实现当失去焦点时,暂停,等恢复获得焦点后,继续播放
下面是通过 ArrayList 一个数组列表(List+ArrayAdapter实现),看不懂没关系,主要理解当点击时,先获取 AudioFocus 状态,根据焦点状态进行判断
package com.example.android.miwok;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import java.util.ArrayList;
public class NumbersActivity extends AppCompatActivity {
//定义一个音频管理的对象
private AudioManager mAudioManager;
//创建一个监听音频聚焦的监听器
AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener =
new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int i) {
//判断当状态 暂时失去音频焦点 暂停并并重置
if(i==AudioManager.AUDIOFOCUS_LOSS_TRANSIENT||
i==AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK){
mediaPlayer.pause();
mediaPlayer.seekTo(0);
}else
//判断当状态获取音频焦点时应该播放
if(i==AudioManager.AUDIOFOCUS_GAIN){
mediaPlayer.start();
}else
//当前状态 永远失去焦点的时候 释放资源
if(i==AudioManager.AUDIOFOCUS_LOSS){
releaseMediaPlayer();
}
}
};
private MediaPlayer mediaPlayer;
//???有必要吗?
private MediaPlayer.OnCompletionListener mCompletionListener = new
MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
releaseMediaPlayer();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.word_list);
//获取AudioManager
mAudioManager = (AudioManager) getSystemService(this.AUDIO_SERVICE);
//自定义的数组列表 类型是Word类的数据
final ArrayList<Word> words = new ArrayList<Word>();
words.add(new Word("one", "lutti", R.drawable.number_one, R.raw.number_one));
words.add(new Word("two", "otiiko", R.drawable.number_two, R.raw.number_two));
words.add(new Word("three", "tolookosu", R.drawable.number_three, R.raw.number_three));
words.add(new Word("four", "oyyisa", R.drawable.number_four, R.raw.number_four));
words.add(new Word("five", "massokka", R.drawable.number_five, R.raw.number_five));
words.add(new Word("six", "temmokka", R.drawable.number_six, R.raw.number_six));
words.add(new Word("seven", "kenekaku", R.drawable.number_seven, R.raw.number_seven));
words.add(new Word("eight", "kawinta", R.drawable.number_eight, R.raw.number_eight));
words.add(new Word("nine", "wo’e", R.drawable.number_nine, R.raw.number_nine));
words.add(new Word("ten", "na’aacha", R.drawable.number_ten, R.raw.number_ten));
//自定义的一个适配器,继承以前的数组适配器
WordAdapter itemsAdapter = new WordAdapter(this, words, R.color.category_numbers);
ListView listView = (ListView) findViewById(R.id.list);
listView.setAdapter(itemsAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Word word = words.get(i);
//request 获取Audio Focus
int result=mAudioManager.requestAudioFocus(mAudioFocusChangeListener
, AudioManager.STREAM_MUSIC
, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
//成功的焦点更改请求
if(result==AudioManager.AUDIOFOCUS_REQUEST_GRANTED){
//创建一个MediaPlayer
mediaPlayer = MediaPlayer.
create(NumbersActivity.this, word.getMusicResource());
//开始播放
mediaPlayer.start();
//
mediaPlayer.setOnCompletionListener(mCompletionListener);
}
}
});
}
@Override
protected void onStop() {
super.onStop();
releaseMediaPlayer();
}
// 自定义的一个释放资源的类
private void releaseMediaPlayer() {
// If the media player is not null, then it may be currently playing a sound.
if (mediaPlayer != null) {
// Regardless of the current state of the media player, release its resources
// because we no longer need it.
mediaPlayer.release();
// Set the media player back to null. For our code, we've decided that
// setting the media player to null is an easy way to tell that the media player
// is not configured to play an audio file at the moment.
mediaPlayer = null;
//失去焦点
mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
}
}
}