在 activity 销毁之前检测旋转(方向变化)

Detect rotation (orientation change) before activity destroyed

目标

我正在开发一个简化的音频播放器,如果用户离开应用程序(主页按钮、任务切换、任务中断、屏幕关闭等),它需要停止播放。我可以让音频继续在后台播放并调出带有暂停/停止选项的通知栏,但我的用户几乎不了解计算机,有些人可能无法在没有帮助的情况下停止音频。

问题

为了停止音频,我需要知道应用程序何时在 activity 被销毁之前移出焦点。 Android 提供了两种方法 onStop 和 onPause 来指示正在发生的事情,而不是什么。如果可能的话,我怎么知道 activity 何时因方向改变而被销毁?

失败的解决方案

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

IsChangingConfigurations 是一个有趣的函数,可以解决我的问题,但这需要 API11,我有兴趣支持 API10。

另一个解决方案似乎很糟糕。 OrientationChangeListener,如 this solution ,看起来很理想,但它只注意到在 activity 关闭并重新启动后方向发生了变化。

与上述选项类似,onConfigurationChanged 仅在方向发生变化后报告。

有缺陷但可能的解决方案

一种解决方案是在失去与 activity 的连接时发出媒体播放器服务通知,然后在设定的时间后自动暂停。这绝对是一个可行的解决方案,但并不理想。多少时间合适?如果平板电脑 运行 缓慢并且旋转时间比平时长,会发生什么情况?如果没有更好的选择,我将退回到这个解决方案。这似乎是一个 hack 并且容易出错。

在发布我的问题之前经过大量搜索,我终于想出了一个基于 this post 的解决方案。我非常简单地检查当前方向并将其与之前的状态进行比较。

getResources().getConfiguration().orientation

如果不同,则 activity 由于旋转而重新启动。

示例解决方案

我首先使用两个成员变量来跟踪先前的配置并标记旋转:

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

当 activity 启动时,在 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...
        }
    }
}

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

我在我的片段中使用它(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();
}