2

I have a progress bar (swirly waiting style) defined in xml as:

<ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@android:style/Widget.Holo.ProgressBar.Large"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/progress"
        />

I hide it's visibility in the activity's onCreate method using,

progressBar.setVisibility(View.GONE);

and start it on a button's onClick event using

progressBar.setVisibility(View.VISIBLE);

Now if I change the screen oreintation the progress bar disappears. I understand that the activity is destroyed and recreated on an orientation change, and the state of the activity is recreated in the new orientation from the saved Bundle savedInstanceState. So am I right in thinking that the default Bundle saved by android does not include any changes made to to a ProgressBar View object?

If this is the case, is it correct to say that the only way to reinstate the correct visibility of the ProgressBar after an orientation change is to save a flag (e.g. boolean pbState = false/true) by overriding the method onSaveInstanceState and inspecting this flag in onRestoreInstanceState and setting the visibility accordingly? Or, am I missing something really obvious about saving the state of view objects.

Thanks

UPDATE:

Both the solutions provided below work. I decided to opt for putting android:configChanges="orientation|screenSize" in the manifest xml file. However, the documentation states that this method should only be used as a last resort. My activity is fairly simple, and so the manifest xml method reduces the amount of code required in the main activity, i.e., no onRestoreInstanceState method. I presume if you're activity is more complex, you'll probably want to explicitly define any state changes using the latter method.

James B
  • 8,975
  • 13
  • 45
  • 83
  • You need to Show progress bar even if orientation changed? – Piyush Aug 21 '13 at 10:10
  • The progress bar is being used to show that a user is being logged in, i.e., an `IntentService` is running doing some server stuff. If the server is taking its time and the user happens to change orientation, the progress bar is lost. It's not critical, but helping me to understand the workings of android. – James B Aug 21 '13 at 10:17

3 Answers3

7

So am I right in thinking that the default Bundle saved by android does not include any changes made to to a ProgressBar View object?

You are right. Android will not save the state of progressBar, or any other widget for that matter.

[Is] it correct to say that the only way to reinstate the correct visibility of the ProgressBar after an orientation change is to save a flag (e.g. boolean pbState = false/true) by overriding the method onSaveInstanceState and inspecting this flag in onRestoreInstanceState and setting the visibility accordingly?

Absolutely. About onRestoreInstanceState(Bundle): You can do without overriding this method. To confirm orientation change, check for savedInstanceState ==> Bundle passed to onCreate(Bundle) against null. If an orientation change has occurred, savedInstanceState will not be null. On start of an activity, savedInstanceState will be null. Following code (which is basically what you proposed) should do the job:

Declare a global boolean variable:

boolean progressBarIsShowing;

In your onCreate(Bundle):

// savedInstanceState != null ===>>> possible orientation change 
if (savedInstanceState != null && savedInstanceState.contains("progressbarIsShowing")) {

    // If `progressBarIsShowing` was stored in bundle, `progressBar` was showing
    progressBar.setVisibility(View.VISIBLE);

} else {

    // Either the activity was just created (not recreated), or `progressBar` wasn't showing
    progressBar.setVisibility(View.GONE);

}

Whenever you show progressBar, set progressBarIsShowing to true. And toggle it when you dismiss progressBar.

Override onSaveInstanceState(Bundle):

if (progressBarIsShowing) {
    outState.putBoolean("progressBarIsShowing", progressBarIsShowing);
}

Caution: Check for when user browses away from your activity(via home button press etc). You might get a BadTokenException if progressBar is showing when the user does so.

Vikram
  • 51,313
  • 11
  • 93
  • 122
  • Thanks Vikram. Yes, this works. Trying to decide which is the best method to implement, i.e., "android:configChanges="orientation .." in maifest file as suggested by Hari, or the method suggested by you. Any thoughts? – James B Aug 21 '13 at 11:03
  • @JamesB Avoid using `android:configChanges="orientation.."`. Here's the reason why: [Link](http://developer.android.com/guide/topics/manifest/activity-element.html#config). Its hard to argue against using `onSaveInstanceState(Bundle)` when the official documentation explicitly warns you about the alternative. Another answer that sheds light on this issue: [Link](http://stackoverflow.com/a/11822367/2558882). – Vikram Aug 21 '13 at 21:55
3

You use the following line inside your activity tag in manifest.

<activity android:name="your activity"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>

In the above android:configChanges="orientation" will maintain the state of your application while configuration change.

Hariharan
  • 24,741
  • 6
  • 50
  • 54
  • 1
    Thanks Hari. I have seen this solution elsewhere, but it doesn't really answer the question as it fixes the orientation, i.e., the user can't change orientation. Agree that this is an option, but I'm trying to understand the workings of Android. – James B Aug 21 '13 at 10:23
  • No it wont fix the orientation. Declaring, android:screenOrientation="portrait" or android:screenOrientation="landscape" will only fix the orientation! – Hariharan Aug 21 '13 at 10:29
  • Thanks Hari. Yes, you're correct - apologies. My only concern is that the documentation warns against using this method - "Using this attribute should be avoided and used only as a last resort". This inclines me to use `onSavedInstance` & `onRestoreInstanceState`, but I'm a novice and may be overly cautious! – James B Aug 21 '13 at 11:00
  • K no probz:) If my answer really helped you to some extent, pls accept it! – Hariharan Aug 21 '13 at 11:03
0

Using android:configChanges is bad practice, because it might get you in much worse trouble.

Also saving a variable at onSaveInstanceState didn't work for me, since you won't get updates while the Activity is destroyed.

I ended up using a ResultReceiver inside a Fragment that doesn't get destroyed by using setRetainInstance(true).

A good article concerning this problem can be found here: https://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

Also see my answer here: https://stackoverflow.com/a/54334864/6747171

Stephan
  • 1
  • 1