Android 9.0失去音频焦点后不能再获取到焦点

问题

在9.0版本上,A先申请音频焦点,B先申请再释放音频焦点后,A也不能收到onAudioFocusChange回调,导致不能继续播放。

但是在7.1版本,这种情况是会正常播放的。

分析过程

查看源码,主要的焦点控制逻辑在MediaFocusControl类,查看B申请焦点requestAudioFocus方法:
其中有调用propagateFocusLossFromGain_syncAf 方法,通知焦点栈中其他元素丢失焦点(也就是A)。

//9.0  8.0 MediaFocusControl.java
    private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr,
            boolean forceDuck) {
        final List<String> clientsToRemove = new LinkedList<String>();
        // going through the audio focus stack to signal new focus, traversing order doesn't
        // matter as all entries respond to the same external focus gain
        for (FocusRequester focusLoser : mFocusStack) {
            final boolean isDefinitiveLoss =
                    focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);
            if (isDefinitiveLoss) {
                clientsToRemove.add(focusLoser.getClientId());
            }
        }
        for (String clientToRemove : clientsToRemove) {
            removeFocusStackEntry(clientToRemove, false /*signal*/,
                    true /*notifyFocusFollowers*/);
        }
    }

看上去已经很像了,先判断栈内元素是否要remove, 然后遍历remove。

//9.0 8.0 FocusRequest.java
    boolean handleFocusLossFromGain(int focusGain, final FocusRequester frWinner, boolean forceDuck) {
        final int focusLoss = focusLossForGainRequest(focusGain);
        handleFocusLoss(focusLoss, frWinner, forceDuck);
        return (focusLoss == AudioManager.AUDIOFOCUS_LOSS);
    }

    private int focusLossForGainRequest(int gainRequest) {
        switch(gainRequest) {
            case AudioManager.AUDIOFOCUS_GAIN:
                switch(mFocusLossReceived) {
                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    case AudioManager.AUDIOFOCUS_LOSS:
                    case AudioManager.AUDIOFOCUS_NONE:
                        return AudioManager.AUDIOFOCUS_LOSS;
                }
            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
                switch(mFocusLossReceived) {
                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    case AudioManager.AUDIOFOCUS_NONE:
                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
                    case AudioManager.AUDIOFOCUS_LOSS:
                        return AudioManager.AUDIOFOCUS_LOSS;
                }
            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
                switch(mFocusLossReceived) {
                    case AudioManager.AUDIOFOCUS_NONE:
                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
                    case AudioManager.AUDIOFOCUS_LOSS:
                        return AudioManager.AUDIOFOCUS_LOSS;
                }
            default:
                Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
                        return AudioManager.AUDIOFOCUS_NONE;
        }
    }

focusLossForGainRequest 根据新申请的应用B的参数返回其他应用A的丢失焦点,判断如果拿到的是AUDIOFOCUS_LOSS,则将其从栈中移除。

然而对于7.0来说 没有移出栈这个过程:

    private void propagateFocusLossFromGain_syncAf(int focusGain) {
        // going through the audio focus stack to signal new focus, traversing order doesn't
        // matter as all entries respond to the same external focus gain
        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
        while(stackIterator.hasNext()) {
            stackIterator.next().handleExternalFocusGain(focusGain);
        }
    }

总结

在8.0以上系统,如果一个应用申请音频焦点使用的是AudioManager.AUDIOFOCUS_GAIN,则其他应用会失去焦点,且被音频焦点栈中移除,后续也不再受到回调,也就不能自动获取焦点了。

因为我们的需求不是很强烈,就没有修改。可以考虑根据使用场景对第二个申请焦点的应用改用AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE或者AUDIOFOCUS_GAIN_TRANSIENT.如果是系统厂商也可以考虑对上面修改源码。

其他

详细的音频焦点流程可参考网上7.0的分析文档

Android音频焦点详解(上)
Android音频焦点详解(下)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在React Native中,遇到Android 9.0以上版本无法进行HTTP请求的问题,可以尝试以下解决方法: 1. 添加网络安全配置文件:Android 9.0以后,Google要求所有的网络请求必须使用HTTPS,为了解决这个问题,需要在应用的res目录下创建一个XML文件,命名为`network_security_config.xml`。文件内容如下: ``` <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config> ``` 2. 在AndroidManifest.xml文件中添加网络安全配置:在`application`标签内添加以下代码: ``` <application ... android:networkSecurityConfig="@xml/network_security_config" ...> ``` 这样做将允许应用发送非加密的HTTP请求。 3. 检查资源文件路径:尽管Android称之为资源文件路径问题相对不太常见,但是有时候路径的问题可能导致HTTP请求无法正常工作。因此,请确保在代码中使用的资源文件的路径是正确的。 4. 检查网络连接权限:确保在AndroidManifest.xml文件中已经添加了网络连接的权限,代码如下: ``` <uses-permission android:name="android.permission.INTERNET" /> ``` 5. 检查网络连接状态:有时候,即使在代码中正确地设置了HTTP请求,但是如果设备没有连接到互联网,仍然无法发送或接收请求。因此,请确保设备在进行HTTP请求时连接到有效的网络。 希望以上解决方法能够帮助到你,使你能够在React Native中成功进行HTTP请求。如果问题仍然存在,请进一步检查相关代码和日志以寻找其他潜在问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值