在活动销毁之前检测旋转(方向更改)

8

目标

我正在开发一个简化的音频播放器,需要在用户离开应用程序(如按下主按钮、切换任务、任务中断、关闭屏幕等)时停止播放。我可以让音频在后台继续播放,并显示一个通知栏,提供暂停/停止选项,但我的用户基本上不懂电脑,有些人可能无法在没有帮助的情况下停止音频。

问题

为了停止音频,我需要在活动被销毁之前知道应用程序何时失去焦点。Android提供了两种方法onStop和onPause,表示某些事情正在发生,但不知道具体情况。如果可能的话,如何知道活动正在被销毁以进行方向更改?

失败的解决方案

我可以在onPause(或onStop / onDestroy)中使用isFinishing()来检查应用程序是否正在关闭并停止音频。但这只告诉我们应用程序何时关闭。它不能区分移动到后台和旋转。

IsChangingConfigurations是一个有趣的函数,可能会解决我的问题,但它需要API 11,我想支持API 10。

另一种解决方案似乎像是一个糟糕的错误修补。OrientationChangeListener,例如这个解决方案,看起来很理想,但它只会在活动关闭并重新启动后才会注意到方向已更改。

与上述选项类似,onConfigurationChanged仅在进行更改后报告方向更改。

存在缺陷但可行的解决方案

一个解决方案是让媒体播放器服务注意到它何时失去与活动的连接,然后在一定时间后自动暂停。这肯定是一个可行的解决方案,但不是理想的解决方案。多长时间才合适?如果平板电脑运行缓慢,旋转需要比平常长的时间怎么办?如果没有更好的选择,我将退回到这个解决方案。这似乎是一个错误的修补程序,容易出错。


为什么不在清单文件中的<activity>声明中添加android:configChanges="orientation|keyboard|keyboardHidden",这样Android就会在不销毁您的活动的情况下调用onConfigurationChanged()。然后您可以自己处理配置更改。 - David Wasser
2个回答

18

我在我的片段(api 11+,但您可以手动决定如何处理旧版本)中使用这个:

@Override
public void onPause() {
    super.onPause();
    if (isRecreating()) {
        //do smth
    }
}

public boolean isRecreating() {
    //consider pre honeycomb not recreating
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
            getActivity().isChangingConfigurations();
}

不错。由于需要支持API 10,我甚至没有查看那个函数。 - David
当键盘可用性或语言发生更改时,这也会触发此操作:https://developer.android.com/guide/topics/resources/runtime-changes.html - Rafal Zawadzki
@RafałZawadzki 是的,但键盘更改不会暂停活动,我认为。 - j2esu
我想找到旋转的活动或另一个活动进入前景。您的解决方案对我很有帮助。我的问题是否有更好的解决方式? - amin

2

在发布问题之前大量搜索后,我终于基于此贴找到了一个解决方案。我简单地检查当前方向并将其与先前状态进行比较。

getResources().getConfiguration().orientation

如果不同,活动将由于旋转而重新启动。

示例解决方案

我首先有两个成员变量来跟踪以前的配置和标记旋转:

private int previousOrientation = Configuration.ORIENTATION_UNDEFINED;
private boolean rotating = false;

当活动启动时,在onCreate中,我调用checkAndSetOrientationInfo(),其定义如下:

private void checkAndSetOrientationInfo() {
    int currentOrientation = getResources().getConfiguration().orientation;
    debugDescribeOrientations(currentOrientation);
    if(previousOrientation != Configuration.ORIENTATION_UNDEFINED // starts undefined
            && previousOrientation != currentOrientation) rotating = true;

    previousOrientation = currentOrientation;
}

支持的功能包括:
private String getOrientationAsString(final int orientation) {
    if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
        return "Landscape";
    } else if(orientation == Configuration.ORIENTATION_PORTRAIT) {
        return "Portrait";
    } else return "Undefined";
}

private void debugDescribeOrientations(final int currentOrientation) {
    Log.v("Orientation", "previousOrientation: " + getOrientationAsString(previousOrientation));
    Log.v("Orientation", "currentOrientation: " + getOrientationAsString(currentOrientation));
}

最后,对于onPause:

@Override
protected void onPause() {
    super.onPause();
    if (isFinishing()) {
        Log.v("onPause", "Finishing");
    } else {
        checkAndSetOrientationInfo();
        if (rotating) {
            Log.v("onPause", "Rotating");
        } else {
           Log.v("onPause", "Not rotating (task switch / home etc)");
           // TODO put code here to pause mediaPlayer etc...
        }
    }
}

我提出并回答了这个问题,以帮助其他遇到同样问题的人。我也很想看到有关这段代码可能失败或其他更好解决方案的评论。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接