19

In my Activity some external thing (service) need to be destroyed in onDestroy(). But I do not want this when configuration change happens (e.g. keyboard flips out) because it will be restored right away.

So the question is: how to distinguish whether onDestroy() is caused by say Back-key press or part of config change process?

after @CommonsWare's answer it would be pretty simple) something like:

@Override 
onDestroy() { 
  if (mIsChangeConfig == true) { 
    mIsChangeConfig = false: 
  } else { 
    stopService(); 
  } 
} 

@Override 
onRetainNonConfigurationInstance() { 
  mIsChangeConfig = true; 
}
German Latorre
  • 10,058
  • 14
  • 48
  • 59
Mix
  • 3,081
  • 2
  • 17
  • 14

3 Answers3

25

In Android 3.x (API Level 11), you can call isChangingConfigurations() to see if the activity is being destroyed due to a configuration change.

Prior to that, override onRetainNonConfigurationInstance() and set a boolean data member (e.g., isChangingConfigurations) to true, and check that data member in onDestroy().

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks, I got an idea... the only trick left is how to clear this flag off, but hope I'll figure it out) – Mix Jul 17 '11 at 20:50
  • 4
    Also, if using the support library FragmentActivity (android.support.v4.app.FragmentActivity) on pre-Honeycomb, onRetainNonConfigurationInstance() is declared final, but you can override onRetainCustomNonConfigurationInstance() instead for the same effect. (This is slightly non-obvious because the deprecated tag takes you to a completely different API that cannot be used in this way.) – benkc Jan 16 '13 at 20:57
  • 6
    If I understand the documentation correctly then `isChangingConfigurations()` is available already in `onStop()` but `onRetainNonConfigurationInstance()` is called between `onStop()` and `onDestroy()`, if at all. So these options are unfortunately not entirely equivalent. – Kaarel Jan 18 '13 at 23:25
  • how would you check it in the onCreate method? – android developer Aug 20 '13 at 15:07
  • 1
    @CommonsWare what's the difference between using isChangingConfigurations() and isFinishing()? – android developer Mar 28 '14 at 13:05
  • @CommonsWare I mean the logic. instead of using isChangingConfigurations, I could use !isFinishing , which is supported from before API11 ? are the equivalent in case I use them in the onDestroy method (except for returning the opposite) ? – android developer Mar 28 '14 at 13:12
  • @androiddeveloper: Well, in the source code, they are independent -- it's not like `isChangingConfigurations()` is implemented as `!isFinishing()`. Probably most of the time your assumption will hold, but I would not be surprised if there are edge cases in which it does not. – CommonsWare Mar 28 '14 at 13:31
  • 1
    @CommonsWare Yes I thought so, but I can't think of any kind of end case. – android developer Mar 28 '14 at 13:38
6

This may do the trick for you (from How to distinguish between orientation change and leaving application android):

Use the Activity's isFinishing() method.

Sample code:

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

  if (isFinishing()) {
    // Do stuff
  } else { 
    // It's an orientation change.
  }
}
Community
  • 1
  • 1
German Latorre
  • 10,058
  • 14
  • 48
  • 59
  • 1
    This is also possible. I wonder though what's the difference between using it and "isChangingConfigurations" (aside from them being the opposite of each other). – android developer Mar 28 '14 at 13:04
  • `!isFinishing()` implies either an orientation change *or* going into the backstack. – Kevin Krumwiede Sep 02 '14 at 23:18
  • it's better to call isFinishing in onPause as onDestroy may not always be called according to the docs at https://developer.android.com/reference/android/app/Activity.html#onDestroy() : Note: do not count on this method being called as a place for saving data! – morgwai Feb 08 '17 at 17:56
0

I have a workaround for the cases when something X has to be done on onStop(), but you don't want it to be done if there is a configuration change (and obviously you don't have isChangingConfigurations() available).

The technique consists on doing this X action on an AsyncTask and delayed. You call the AsyncTask in onStop()/onPause() and in onRetainCustomNonConfigurationInstance() you cancel the task. This way, if the user presses the home key, for example, the X code will be executed on background . However, if there is a screen rotation, the X code will not be executed because the task will be cancelled before it's executed (that's the meaning of the delay).

I'm using it for example to solve problems with wakelocks: releasing them on onPause() but not if the user changes the screen orientation.

Here is my code:

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);
    }
}

Hope it helps!

Pek Ifly
  • 89
  • 3