MediaPlayer的唤醒锁





  一般使用MediaPlayer播放音频流,推荐使用一个Service来承载MediaPlayer,而不是直接在Activity里使用。可是Android系统的功耗设计里,为了节约电池消耗,假设设备处于睡眠状态。系统将试图减少或者关闭一些没设备必须的特性。包含CUP和Wifi硬件。然后,假设是一个后台播放音乐的应用,减少CUP可能导致在后台执行的时候干扰音频的正常播放。关闭Wifi将可能导致网络音频流的获取出现错误。



  为了确保MediaPlayer的承载的服务在系统睡眠的时候继续正常执行下去。Android为我们提供了一种唤醒锁(wake locks)的机制。它能够在系统睡眠的,依旧保持锁定硬件的正常工作。

  确保在MediaPlayer执行的时候,哪怕系统睡眠了CUP也能正常执行。须要使用MediaPlayer.setWakeMode()为MediaPlayer设定唤醒锁。以下是setWakMode()的签名:

  setWakeMode(Context context, int mode)

  第一个參数是当前上下文,第二个參数为须要加锁的状态,被设定为int类型的常量,定义在PowerManager这个final类中。

PowerManager是专门用来管理Android功率消耗的锁定状态,与锁定CUP相关的,有四种,分别设定CUP、屏幕、键盘等的各种保持唤醒的状态。在这里仅仅须要设定为PARTIAL_WAKE_LOCK就可以。

mediaPlayer = new MediaPlayer();
// 设定CUP锁定
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

一般对于锁而言。锁定了通常须要解锁。可是这里的唤醒说与MediaPlayer关联,所以仅仅须要在使用完之后release()释放MediaPlayer就可以,无需显式的为其解锁。在使用setWakeMode设定唤醒锁的时候,还必须为应用赋予对应的权限:

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

再来说说怎样锁定wifi硬件在系统睡眠的时候保持正常执行。wifi锁通过WifiLock进行操作,而WifiLock通过WifiManager进行管理,通过WifiManager.createWifiLock()进行Wifi锁定。



    WifiManager.WifiLock createWifiLock(int lockType, String tag)



  这种方法有多个重载。这里介绍的这个,第一个參数设定锁的状态,为一个int类型的常量,定义在Context类中,这里的应用场景一般设定为WIFI_MODE_FULL就可以。

第二个參数为WifiLock的标志,用于确定wifiLock的。

wifiLock= ((WifiManager) getSystemService(this.WIFI_SERVICE)).createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
wifiLock.acquire();

当然,在应用中把Wifi锁定之后。还须要在MediaPlayer.release()的时候为wifi硬件解锁。为避免意外关闭的情况,最好在Android组件的onDestory()里对其进行释放,释放Wifi锁使用WifiLock.release()。

/**
* 停止播放
*/
protected void stop() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
// 释放wifi锁
wifiLock.release();
btn_play.setEnabled(true);
Toast.makeText(this, "停止播放", 0).show();
} } @Override
protected void onDestroy() {
// 在activity结束的时候回收资源
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
// 释放wifi锁
wifiLock.release();
}
super.onDestroy();
}

MediaPlayer的音频焦点





  众所周知,Android是一个多任务的操作系统。所以对于音频的播放。或许有几个不同的媒体服务会同一时候播放,这样可能导致一个比較杂乱的声音环境,而错过一些重要的声音提醒。在Android2.2之后,Android提供了一种应用协商使用设备音频输出的机制。这样的机制称为音频焦点。





  当应用程序须要输出音频或通知的时候,须要请求音频焦点,当请求得到音频焦点之后,监听音频焦点的变换,当音频焦点变换了,依据返回回来的音频焦点码进行对应的处理。音频焦点的注冊使用音频管理器的AudioManager.requestAudioFocus()方法设定。

它的签名例如以下:





    int requestAudioFocus(AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint)





  这种方法的返回值是int类型,其含义被定义在AudioManager中以常量表示AUDIOFOCUS_REQUEST_FAILED(获取音频焦点成功)、AUDIOFOCUS_REQUEST_GRANTED(获取音频焦点失败)。

当中重要的是第一个參数。为音频焦点变化的回调函数。在当中能够设定假设音频焦点变换了。当前应用怎样管理MediaPlayer。第二个參数为媒体流的类型,第三个參数为持续的状态。

  AudioManager.OnAudioFocusChangeListener为音频焦点变换的监听器,当中须要实现一个方法:onAudioFocusChange(int focusChange)在音频焦点变换的时候回调。它有一个參数,为当前表示音频焦点对于当前应用的状态码。通过这个状态码指定相应的操作,有些时候音频状态改变了,并不一定须要停止音频的播放。

  focusChange有一下几种状态码:





AUDIOFOCUS_GAIN:获得音频焦点。

AUDIOFOCUS_LOSS:失去音频焦点。而且会持续非常长时间。这是我们须要停止MediaPlayer的播放。

AUDIOFOCUS_LOSS_TRANSIENT:失去音频焦点,但并不会持续非常长时间,须要暂停MediaPlayer的播放。等待又一次获得音频焦点。

AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:临时失去音频焦点,可是无需停止播放,仅仅需减少声音方法。

 audioManager = (AudioManager) getSystemService(this.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(
new OnAudioFocusChangeListener() { @Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// 获得音频焦点
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
// 还原音量
mediaPlayer.setVolume(1.0f, 1.0f);
break; case AudioManager.AUDIOFOCUS_LOSS:
// 长久的失去音频焦点,释放MediaPlayer
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// 展示失去音频焦点,暂停播放等待又一次获得音频焦点
if (mediaPlayer.isPlaying())
mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// 失去音频焦点,无需停止播放,减少声音就可以
if (mediaPlayer.isPlaying()) {
mediaPlayer.setVolume(0.1f, 0.1f);
}
break;
}
}
}, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);

总结

  以上就解说了MediaPlayer的一些高级的内容,在掌握了MediaPlayer的使用之后。开发有关音乐播放类的应用的时候就能够得心应手了。

从用户体验的方面出发,假设真实开发一款播放器类的软件,须要监听AUDIO_BECOMING_NOISY的广播,它会在音频输出源从其它输出源变换到设备扬声器的时候发出此广播。监听广播在音频输出源改变到设备扬声器的时候。停止播放。这样确保在耳机或额外的音频输出硬件与设备断开连接的时候。不至于又一次从扬声器继续输出音频播放。

源代码链接:http://download.csdn.net/detail/duanyu218/7475569

Android多媒体-MediaPlayer唤醒锁及音频焦点的更多相关文章

  1. Android 多媒体MediaPlayer使用详解

    现在的手机功能越来越丰富了,遥想10年前,MP3,MP4,MP5,还是很流行的,博主当时读高中时很想拥有一台,可以听音乐和看电影.可是条件有限,学校也禁止此东西,所以只能偷偷的玩.而现在我们的手机也很 ...

  2. Android异常:唤醒锁未授权。(Caused by: java.lang.SecurityException: Neither user 10044 nor current process has android.permission.WAKE_LOCK.)

    Android异常:Caused by: java.lang.SecurityException: Neither user 10044 nor current process has android ...

  3. 【Android Developers Training】 45. 控制音频焦点

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android 多媒体应用】使用MediaRecoder录制,MediaPlayer播放音频数据

    1.MainActivity.java import android.annotation.TargetApi; import android.app.Activity; import android ...

  5. Android音频焦点详解(上)

    转载请注明出处:http://www.cnblogs.com/landptf/p/6384112.html 2017年开年第一篇博客,很早就想总结一下Android音频的相关知识.今天我们先来看一下音 ...

  6. Android音频焦点处理相关的方法

    有这么一种场景:你打开qq音乐.优酷客户端.视频播放的时候.这个时候突然来电显示了,此时所有的MediaPlayer相关的服务或者响应都进入"休眠"状态.那么,这个功能是怎么实现的 ...

  7. 【Android 多媒体开发】 MediaPlayer 状态机 接口 方法 解析

    作者 : 韩曙亮 转载请著名出处 :  http://blog.csdn.net/shulianghan/article/details/38487967 一. MediaPlayer 状态机 介绍 ...

  8. Android音乐编程:管理音频焦点

    Android 系统保持相互独立的音频流通道来播放音乐,报警,通知,来电铃声,系统声音,呼叫(通话)音量,和 DTMF 音调(键盘拨号).这样做主要是为了使用户能够独立地控制每个流的音量. AD: h ...

  9. Android学习笔记_24_多媒体MediaPlayer对象之音乐播放器与SoundPool声音池

    一.MediaPlayer对象常用方法介绍: MediaPlayer mediaPlayer = new MediaPlayer(); if (mediaPlayer.isPlaying()) { m ...

随机推荐

  1. JavaScript 原生代码找对象的方法

    1. id :  document.getElementById('id') 2. 标签 : document.getElementsByTagName('标签') //获得的是一个标签数组 3. N ...

  2. 如何优化LIMIT

    首先我们先创建个数据表做测试 表名 test (id(int) , name(var char) , content(text) , pid(int) ) 往里面倒几百万条数据进去做测试. 我们都知道 ...

  3. CAD参数绘制实心圆弧填充(com接口)

    C#中实现代码说明: private void DrawPathToHatch1() { //把路径的开始位置移动指定的点 //参数一为点的X坐标 ,参数二为点的Y坐标,参数三为该点处开始宽度,对Po ...

  4. 19Web服务

    Web服务 Web服务 Micosoft.Net平台架构中的分布式系统主要包括两部分:用ASP.Net技术构建服务器端动态网页,以及Web服务(Web Service或XML Web Service) ...

  5. vuex如何管理需要即时更新的全局变量

    自己在使用vue练习开发的时候遇到全局变量无法即时更新的问题,查了资料之后得出结论使用vuex能够快速解决该问题,但是看了好多人讲解vuex的教程自己跟着去做都没解决自己想要的,最后找到一个比较容易理 ...

  6. 笔试算法题(40):后缀数组 & 后缀树(Suffix Array & Suffix Tree)

    议题:后缀数组(Suffix Array) 分析: 后缀树和后缀数组都是处理字符串的有效工具,前者较为常见,但后者更容易编程实现,空间耗用更少:后缀数组可用于解决最长公共子串问题,多模式匹配问题,最长 ...

  7. idea导入本地idea的web项目(服务器用的是tomcat)

    开始吧!!! 点击import project. 我以SpringMVCPro3为例,选中,点击OK 点击next 继续next 随便吧,我点击yes 选中工程,点击next lib1不要钩,然后点击 ...

  8. linux文件及目录的权限管理

    一.文件的权限 1.文件权限的查看 命令:ls -l 可以使用ll命令代替 ls -l 2.ls -l 所包含的信息 (1)权限信息 (-rw-r--r-- ) 一共有10位 a.第一位:表示文件信息 ...

  9. this关键字的由来及使用

    Student.java /* * 学生类 * * 起名字我们要求做到见名知意. * * 如果有局部变量名和成员变量名相同,在局部使用的时候,采用的是就近原则. * *我们有没有办法吧局部变量的nam ...

  10. EGit应用

    [创建Dynamic Web Project项目] [创建仓库] 项目(鼠标右键) ==〉Team==〉Share Project..... ==〉选择Git 配置Repository的目录 创建完成 ...