Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect rotation (orientation change) before activity destroyed

Goal

I'm working on a simplified audio player needs to stop playing if the user moves away from the application (home button, task switch, task interruption, screen off etc). I could have the audio continue to play in the background and bring up a notification bar with pause / stop options, but my users are barely computer literate and some might have trouble stopping the audio without assistance.

Problem

In order to stop the audio, I need to know when the application is moving out of focus before the activity is destroyed. Android provides two methods onStop and onPause which indicate something is happening, but not what. If it is possible, how do I know when the activity is being destroyed for an orientation change?

Failed Solutions

I can use isFinishing() within onPause (or onStop / onDestroy) to check if the application is closing and stop the audio. But this only tells us when the application is closing. It doesn't distinguish between moving into the background and rotating.

IsChangingConfigurations is an interesting function that may solve my problems, but this requires API 11 and I am interested in supporting API 10.

The other solution seems like a bad hack. The OrientationChangeListener, like this solution , seemed ideal, but it it only notices the orientation has changed after the activity has been closed and restarted.

Similar to the above option, onConfigurationChanged only reports orientation changes after they have been made.

Flawed but Possible Solution

One solution is have the media player service notice when it has lost connection to the activity and then automatically pause after a set amount of time. This definitely seems like a workable solution, but it is not ideal. How much time is appropriate? What happens if a tablet is running slowly and the rotate takes longer than usual? I will fall back to this solution if there are no better alternatives. This seems like a hack and prone to error.

like image 762
David Avatar asked Nov 16 '16 18:11

David


2 Answers

I use this in my fragment (api 11+, but you can manually decide what to do with older versions):

@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();
}
like image 173
j2esu Avatar answered Oct 14 '22 05:10

j2esu


After a lot of searching before posting my question, I finally came up with a solution based off of this post. I very simply check the current orientation and compare it to the previous state.

getResources().getConfiguration().orientation

If it is the different, the activity is restarting due to a rotation.

Sample Solution

I start by having two member variables to track the previous configuration and to mark rotation:

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

When the activity is started, in onCreate, I call checkAndSetOrientationInfo() which is defined as:

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

    previousOrientation = currentOrientation;
}

The supporting functions are:

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

And finally, for 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...
        }
    }
}

I asked and answered this question to help others with the same problem. I am also interested to see any comments about situations where this code might fail or other better solutions.

like image 40
David Avatar answered Oct 14 '22 06:10

David