如何区分onDestroy()是作为配置更改序列的一部分被调用的?

19
在我的Activity中,一些外部的事物(服务)需要在onDestroy()方法中被销毁。但是当发生配置更改(例如键盘弹出)时,我不希望这样做,因为它会立即被恢复。
因此问题是:如何区分onDestroy()是由返回键按下还是由配置更改过程的一部分引起的?
在@CommonsWare的回答之后,将会变得非常简单。类似于:
@Override 
onDestroy() { 
  if (mIsChangeConfig == true) { 
    mIsChangeConfig = false: 
  } else { 
    stopService(); 
  } 
} 

@Override 
onRetainNonConfigurationInstance() { 
  mIsChangeConfig = true; 
}

展示一些代码。至少提供伪代码。这并没有提供足够的信息。 - Andrew Anderson
在问题中添加了伪代码... - Mix
3个回答

25

在Android 3.x(API Level 11)中,您可以调用isChangingConfigurations()来查看活动是否因配置更改而被销毁。

在此之前,覆盖onRetainNonConfigurationInstance()并设置一个布尔数据成员(例如,isChangingConfigurations)为true,然后在onDestroy()中检查该数据成员。


4
如果在Honeycomb版本之前使用支持库FragmentActivity (android.support.v4.app.FragmentActivity),则onRetainNonConfigurationInstance()被声明为final,但是您可以覆盖onRetainCustomNonConfigurationInstance()来达到相同的效果。(这稍微不太明显,因为“已弃用”标签会带您进入一个完全不能以此方式使用的不同API。) - benkc
6
如果我正确理解文档,那么 isChangingConfigurations() 已经可以在 onStop() 中使用了,但 onRetainNonConfigurationInstance() 只有在 onStop()onDestroy() 之间被调用(如果需要的话)。因此,这两个选项不完全等效。 - Kaarel
1
@CommonsWare 两者之间使用isChangingConfigurations()和isFinishing()有什么区别? - android developer
@CommonsWare 我的意思是逻辑。我可以使用!isFinishing代替isChangingConfigurations,这在API11之前就受支持了?如果我在onDestroy方法中使用它们,它们是否等效(除了返回相反的结果)? - android developer
1
@CommonsWare 是的,我也这么想,但我想不出任何一种结束情况。 - android developer
显示剩余3条评论

6
这可能对你有帮助(来自如何区分android的方向更改和离开应用程序):

使用Activity的isFinishing()方法。

示例代码:

@Override
protected void onDestroy() {
  super.onDestroy();

  if (isFinishing()) {
    // Do stuff
  } else { 
    // It's an orientation change.
  }
}

1
这也是可能的。不过我想知道使用它和“isChangingConfigurations”之间有什么区别(除了它们互为相反)。 - android developer
!isFinishing() 意味着要么是屏幕方向改变,要么 是进入了后台堆栈。 - Kevin Krumwiede
最好在onPause中调用isFinishing,因为根据https://developer.android.com/reference/android/app/Activity.html#onDestroy()文档,不一定总是会调用onDestroy。请注意:不要指望这个方法被当做保存数据的地方! - morgwai

0

当需要在onStop()上执行某些操作X,但是如果有配置更改(显然没有isChangingConfigurations()可用),则不希望执行它时,我有一个解决方法。

这种技术的做法是使用AsyncTask并延迟执行X操作。您可以在onStop()/onPause()中调用AsyncTask,在onRetainCustomNonConfigurationInstance()中取消任务。这样,如果用户按下Home键,例如,X代码将在后台执行。但是,如果屏幕旋转,则X代码不会被执行,因为任务将在执行之前被取消(这就是延迟的含义)。

例如,我正在使用它来解决wakelocks问题:在onPause()上释放它们,但如果用户更改屏幕方向,则不释放。

以下是我的代码:

private class ReleaseWakeLockDelayedTask extends AsyncTask<WakeLock, Integer, Integer>{

    @Override
    protected Integer doInBackground(WakeLock... params) {

        try {
            // Delay so that onRetainCustomNonConfigurationInstance is in
            //  time of cancelling the task
            Thread.sleep(5000);  
        } catch (InterruptedException e) {}

        if(isCancelled()) return null;
        releaseWakeLock(params[0]); // own method that calls the actual release
        return null;
    }
}


@Override
public Object onRetainCustomNonConfigurationInstance() {
    ...
    if(mReleaseWakeLockTask != null && mReleaseWakeLockTask .getStatus() != AsyncTask.Status.FINISHED){
        mReleaseWakeLockTask.cancel(true));
    }
    ...
}

@Override
protected void onPause() {
    // create and call the task
    boolean wRun;

    if(mReleaseWakeLockTask != null){
        if(mReleaseWakeLockTask .getStatus() != AsyncTask.Status.FINISHED) wRun= false;
        else wRun= true;
    }else wRun = true;

    if(wRun){
        mReleaseWakeLockTask = new mReleaseWakeLockTask ();
        mReleaseWakeLockTask .execute(wakeLock);
    }
}

希望能对你有所帮助!


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