3

Related questions:


This is a strange behaviour i got in my Activities.

Portrait mode (It's normal)

  1. Press screen lock, Activity: onPause();
  2. Unlock the screen, Activity: onResume().

Landscape mode (It's strange)

  1. Press screen lock, Activity: onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onResume() which loads the Portrait layout;
  2. Unlock the screen, Activity: onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onResume() and loads the Landscape layout.

What I expect is:

Portrait mode: (same)

Landscape mode: (should act like Portrait mode)

  1. Press screen lock, Activity: onPause();
  2. Unlock the screen, Activity: onResume().

So my questions:

  • Why does my Activities behave like this?
  • How does your Activities behave?

Original text description of my question:

While i press the Lock Screen button of my phone, when my Activity is at its Landscape mode, i noticed (in the debug messages i output to Eclipse) the Activity is re-created to its Portrait mode (while the screen is all black, of course). Then when i press the Lock Screen button again to unlock the screen, the Activity was destroyed and re-created to its Portrait again.

As i remember (not 100% sure though), and what i expect is, my Activity should only undergo onSaveInstanceState() and onPause(), while Lock Screen in Landscape mode, like what it does in Portrait mode. Rather than re-creating the Activity to Portrait and going back to Landscape again.

Is it that i have messed up something with my phone? How can i fix it back to normal?

Thanks!


Thanks everyone for contributing into this issue. Especially thanks @HoanNguyen for his effort of testing for me in his devices. And Especially thanks @Raghunandan for having an in-depth discussion with me concerning this issue.

Summarising everyone's contributions so far, i have the following conclusions:

1. This is a normal phenomenon.

It seems that, on mobile phones, the running Activities, that are in Landscape mode, are switched into Portrait mode upon screen lock is a normal behaviour. At least it is true on the tested phones so far. So we have to make sure our lifecycle functions can take care this change elegantly always.

2. Guess this is because of the "default orientation" in the locked screen.

We do not have documentation or many resource talking about this issue. But the assumption that the running Activities switching back to the device's "default orientation" upon screen lock, as in most devices the locked screen is in Portrait, is quite logical.

Further study:

I just wonder how the Activities behave if we are having a landscape locked screen?

Community
  • 1
  • 1
midnite
  • 5,157
  • 7
  • 38
  • 52
  • When screen lock, it seem all the applications will be assumed to have default orientation, – Hoan Nguyen Mar 26 '13 at 23:36
  • Thanks @HoanNguyen for your reply. Have you tested it on your device? If you would quote some references about this assumption, it would be perfect! Thanks a lot! – midnite Mar 27 '13 at 00:19
  • 1
    I tested in 3 phones, one with JB and the other ICS. I do not have any references concerning this. But if you think about it, when the device is flat android would not be able to tell you what is Portrait or Landscape, thus it has to default to the device default orientation. Now if you lock the screen then you may lay it flat, if now the screen is unlock but flat what do you do? – Hoan Nguyen Mar 27 '13 at 00:41
  • Thanks @HoanNguyen very much for the testings! So we can almost conclude this is a "feature" instead of a "strange behaviour" (: i do agree with you there is a need for the default orientation. But upon screen lock, i would expect it keeps the previous orientation, _or_ using the sensor orientation. (So answer to your question would be: previous orientation if flat.) The default orientation should only be used when the phone is initialised (first moment turned on) _and_ is laid flat. – midnite Mar 27 '13 at 00:58

2 Answers2

2

You can stop the activity from restarting on orientation change but this is generally a pretty bad idea.

The Android documentation has a section on handling runtime changes with this note:

Note: Handling the configuration change yourself can make it much more difficult to use alternative resources, because the system does not automatically apply them for you. This technique should be considered a last resort when you must avoid restarts due to a configuration change and is not recommended for most applications.

Android generally only recommends you supress recreating on rotation if you don't need alternate resources and, more importantly, have a performance requirement. A well-designed app shouldn't need to do this in most cases.

If you insist on going down the path of supressing default Android behavior, I'd modify Raghunandan's code and include a screen size attribute as well. As of API level 13, the screen size changes upon orientation change. So you must include screenSize unless you are only targeting API 12 and below.

<activity android:name=".MyActivity"
      android:configChanges="orientation|screenSize"
      android:label="@string/app_name">
yarian
  • 5,922
  • 3
  • 34
  • 48
  • Thanks for your reply. Sorry i didnt make myself clear enough in the first place. Thanks for providing the `android:configChanges` approach also. – midnite Mar 26 '13 at 20:50
0

To avoid activity from restarting

<activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"//add tthis in manifest
      android:label="@string/app_name">

http://developer.android.com/guide/topics/resources/runtime-changes.html.

In normal circumstances when your screen is locked your activity is paused and when screen is unlocked activity resumes.

An issue when screen locked is: Current Activity may be stopped forcefully by the system if it finds shortage of memory, instead of moving Activity to background. In such a case, we should have to save (all the necessary data) the current state of the Activity.

Save you data in onSaveInstanceState() and restore data onRestoreInstanceState().

@Override
 public void  onSaveInstanceState(Bundle outState)
 {
  Log.v("$````$", "In Method: onSaveInstanceState()");
  //if necessary,set a flag to check whether we have to restore or not
  //handle necessary savings…
 }

@Override
public void onRestoreInstanceState(Bundle inState)
{
  Log.v("$````$", "In Method: onRestoreInstanceState()");
  //if any saved state, restore from it…
}

In your onCreate()

IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);

mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter); //register


public class ScreenReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent)
   {
        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
        {    
              Log.v("$$$$$$", "In Method:  ACTION_SCREEN_OFF");
              // onPause() will be called.
        }
        else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
        {
              Log.v("$$$$$$", "In Method:  ACTION_SCREEN_ON");
              //onResume() will be called.
              //Better check for whether the screen was already locked
              // if locked, do not take any resuming action in onResume()
              //Suggest you, not to take any resuming action here.       
        }
        else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT))
        {
              Log.v("$$$$$$", "In Method:  ACTION_USER_PRESENT"); 
              //Handle resuming events
        }
  }

In your onDestroy

  @Override
  public void onDestroy()
  {
        super.onDestroy();
        Log.v("$$$$$$", "In Method: onDestroy()");

        if (mReceiver != null)
        {
              unregisterReceiver(mReceiver); //unregister 
              mReceiver = null;
        }          

  }
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • Thanks for reply. So you are assuming that was caused by a memory shortage? i guess not. i have plenty of memory and i am just testing with a very simple Activity with a line `System.out.println(getResources().getConfiguration().orientation + ":onCreate");` in `onCreate()`. i am not sure with the `IntentFilter` and `BroadcastReceiver`. Could you explain what they are used for? Thanks. – midnite Mar 26 '13 at 19:48
  • I am not assuming it is a case to be considered. We will receive the broadcasted intents for screen lock & unlock.(System wide broadcast). Just try logging something to logcat by overriding onDestory() onPause() and onResume(). You can handle screen lock and unlock. – Raghunandan Mar 26 '13 at 19:51
  • You don't your activity restarting?? – Raghunandan Mar 26 '13 at 19:59
  • hmm... Thanks again. i know and i expect when screen is locked, Activity is paused and resumed after unlock. But i noticed when i am in Landscape mode, the Activity is *recreated* totally!! Is this normal? And a follow up question: Does it mean with the codes you provided, the original onPause() and onResume() will not be called upon screen lock & unlock, and implement codes in those if-else functions instead? – midnite Mar 26 '13 at 20:00
  • Thanks for providing the `android:configChanges` approach. But i just think the Activity should **not** restart when we lock the screen. – midnite Mar 26 '13 at 20:02
  • onPause() will be called when screen is locked. onResume() is called when activity resumes. (if activivty is not destroyed ) – Raghunandan Mar 26 '13 at 20:02
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/26969/discussion-between-raghunandan-and-midnite) – Raghunandan Mar 26 '13 at 20:14