22

I have an aacplayer app and I want to save the state of my activity when orientation changes from portrait to landscape. The TextViews do not appear to be empty, I tried to freeze my textview using this:

android:freezesText="true"

my manifest:

android:configChanges="orientation"

I also tried this:

@Override
    public void onConfigurationChanged(Configuration newConfig){
        super.onConfigurationChanged(newConfig);
        setContentView(R.layout.main2);

So when orientation changes to landscape I can see my layout-land main2.xml, that works but my textview goes out and appears empty. Streaming music works great. I can listen to it when orientation changes, but the text inside textviews are gone each time I change the orientation of my device.

What should I do to fix this so I can save the state?

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
....
....

Thank you very much.

buczek
  • 2,011
  • 7
  • 29
  • 40
alexistkd
  • 906
  • 2
  • 14
  • 34

4 Answers4

61

When your orientation changes, you don't have to manually change to the landscape layout file. Android does this automatically for you. When orientation changes, Android destroys your current activity and creates a new activity again, this is why you are losing the text.

There are 2 parts you need to do, assuming you want a separate layout for portrait and landscape.

  1. Assuming you have 2 XML layout files for portrait and landscape, put your main.xml layout file in the following folders:

    res/layout/main.xml <-- this will be your portrait layout
    res/layout-land/main.xml <-- this will be your landscape layout

    That's all you need to do, you don't have to touch the manifest file to modify android:configChanges="orientation" or override the onConfigurationChanged(). Actually, it's recommended you do not touch this for what you are trying to achieve.

  2. Now to save your text from the text view =) Lets assume your textview is named as MyTextView in your layout xml file. Your activity will need the following:

    private TextView mTextView;
    private static final String KEY_TEXT_VALUE = "textValue";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       mTextView = (TextView) findViewById(R.id.main);
       if (savedInstanceState != null) {
          CharSequence savedText = savedInstanceState.getCharSequence(KEY_TEXT_VALUE);
          mTextView.setText(savedText);
       }
    }
    
    @Override
    protected void onSaveInstanceState (Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putCharSequence(KEY_TEXT_VALUE, mTextView.getText());
    }
    

Basically, whenever Android destroys and recreates your Activity for orientation change, it calls onSaveInstanceState() before destroying and calls onCreate() after recreating. Whatever you save in the bundle in onSaveInstanceState, you can get back from the onCreate() parameter.

So you want to save the value of the text view in the onSaveInstanceState(), and read it and populate your textview in the onCreate(). If the activity is being created for the first time (not due to rotation change), the savedInstanceState will be null in onCreate(). You also probably don't need the android:freezesText="true"

You can also try saving other variables if you need to, since you'll lose all the variables you stored when the activity is destroyed and recreated.

hiBrianLee
  • 1,847
  • 16
  • 19
  • 2
    in case you are not doing it already, whatever object's doing your aac playback should be running in a service, not in your activity. You can also use fragments to have the aac playing as a separate fragment that's retained, and if you are interested in going that approach you can read more about fragments here http://developer.android.com/guide/components/fragments.html – hiBrianLee Oct 23 '12 at 03:26
  • u recommend me to dont use onconfigchanged ? i dont need to add android:configChanges="orientation" ? i do some research here and i found that i need to put that in manifest. – alexistkd Oct 23 '12 at 03:28
  • yeah im already using a service, heres my oncreate code i need to save all so when orientation changes and layout also changes because i have layout-land .xml `http://pastebin.com/4bM4u0C2` – alexistkd Oct 23 '12 at 03:35
  • No, I don't recommend using onConfigChanged. It's basically a hack to get around Android destroying/recreating the activity on rotation change, so it's not good practice. There's a reason why Android is designed to destroy/recreate activity on rotation change, so you want to keep the designed behavior. In the early Android days people used it to get around it as a quick hack. You can basically save anything you want on rotation change that will fit in a bundle, just use different keys and restore them in onCreate() – hiBrianLee Oct 23 '12 at 03:44
  • did u saw my code? `protected void onCreate(Bundle savedInstanceState) {` i need to recreate all that when orientation changes how can achieve that – alexistkd Oct 23 '12 at 03:47
  • i used onconfigchanged because if not when my orientation changes another instance of the stream station starts and i have two audio running – alexistkd Oct 23 '12 at 03:54
  • and if remove `android:configChanges="orientation"` i got the same issue two streams starts at the same time. – alexistkd Oct 23 '12 at 03:57
  • can give me an example please, also i have my textview already like this: `private TextView txtMetaTitle;` – alexistkd Oct 23 '12 at 04:36
  • You can keep what you have in onCreate. You don't want to save all UI element instances (button, textview, etc..). You want them to be recreated. But if there's any values (like text shown on textview), that's what you want to save and load up. I think I answered your original question about how to keep the text on text view on rotation, and this should really be a separate question on how to retain non-UI elements on rotation change (because the answer/explanation will be sort of long and deserves another thread). – hiBrianLee Oct 23 '12 at 16:39
  • Anyway, short explanation is, for your Streaming object, put that in a non-UI fragment, say StreamingFragment. And in StreamingFragment.onCreate(), you'll do setRetainInstance(true). This fragment will have your streaming object. In your main activity, you'll add this StreamingFragment through FragmentManager via findFragmentByTag. If you want to find out more, look into the FragmentRetainInstance example from Google. Your StreamingFragment will be the RetainedFragment in this example - http://goo.gl/yGqCL Check the section on "Adding a fragment without UI" – hiBrianLee Oct 23 '12 at 16:40
  • 1
    If you have more questions on retained fragment, you should start another question thread =) I think your original question about "keeping textview's text on rotation" is answered – hiBrianLee Oct 23 '12 at 16:41
  • Wouldn't it be better to use `Activity#onRestoreInstanceState()` than `Activity#onCreate()`? You wouldn't need to check if there is a previous instance of `Bundle`(savedInstanceState), because `onRestoreInstanceState` is called after `onStart` only if there was a saved state. – klauskpm Oct 19 '16 at 21:38
  • Question: You said `"You can also try saving other variables if you need to, since you'll lose all the variables you stored when the activity is destroyed and recreated"` Does this include variables created by my java code, like the value of a game score? – kbluue Oct 30 '16 at 15:52
  • Also i don't understand how you connected your textview `My TextView` with this part of the code ==> `if (savedInstanceState != null) { CharSequence savedText = savedInstanceState.getCharSequence(KEY_TEXT_VALUE); mTextView.setText(savedText); }` What do i do when i have multiple attributes with states that i want to conserve? – kbluue Oct 30 '16 at 18:14
  • Is `layout-land` is still supported now? I'm trying to used it but it doesn't get the layout I put in `layout-land`. Thank you. – natsumiyu Aug 15 '17 at 01:55
  • as u mentioned there is no need to add `android:configChanges="orientation"` but in my case i use the `configChanges` for avoid the landscape mode in mobiles so how can i fix this issue with adding of `configChanges` in `manifest` file – Dhruv Tyagi Sep 13 '17 at 09:40
  • @hiBrianLee I don't see why I should not use the android:configChanges="orientation" way as even Google itself is using this approach in AOSP. You can see here: https://github.com/aosp-mirror/platform_packages_apps_settings/blob/master/AndroidManifest.xml#L233 – Shivam Jha Oct 29 '18 at 19:17
4

There are two ways of doing this, the first one is in the AndroidManifest.xml file. You can add this to your activity's tag

android:configChanges="keyboardHidden|orientation|screenSize|screenLayout"

Or you can override two methods that will take care of this. This method requires some more effort, but arguably is much better. onSaveInstanceState saves the state of the activity before it's killed, and onRestoreInstanceState restores that information after onStart() Refer to the official documentation for a more in depth look.

In my sample code below, I am saving 2 int values, the current selection from the spinner as well as a radio button.

 @Override
    public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
        spinPosition = options.getSelectedItemPosition();
        savedInstanceState.putInt(Constants.KEY, spinPosition);
        savedInstanceState.putInt(Constants.KEY_RADIO, radioPosition);
        super.onSaveInstanceState(savedInstanceState);

    }

    // And I am restoring those values with `getInt`, then I can pass those stored values into the spinner and radio button group to select the same values that we saved earlier. 

    @Override
    public void onRestoreInstanceState(@NotNull Bundle savedInstanceState) {
        spinPosition = savedInstanceState.getInt(Constants.KEY);
        radioPosition = savedInstanceState.getInt(Constants.KEY_RADIO);
        options.setSelection(spinPosition, true);
        type.check(radioPosition);
        super.onRestoreInstanceState(savedInstanceState);
    }
A P
  • 2,131
  • 2
  • 24
  • 36
1
static CharSequence savedText;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if(savedText != null) {
        TextView mTextView = (TextView) findViewById(R.id.main);
        mTextView.setText(savedText);
    }
}

// Another function in activity, when you change text
public void actionButton(View view) {
    // Change and save text in textView
    savedText = "Change text";
    mTextView.setText(savedText);
}

Its work for me. But I think its not good code style and architecture for android.

Fortran
  • 2,218
  • 2
  • 27
  • 33
0

I use in KOTLIN static var / val :

class MyFragment : Fragment()
{
     //all my code
     //access to static vars -> MyStaticClass.hello
}

class MyStaticClass 
{
    companion object {
        var hello: String = "Static text"
        var number_static: Int = 0
    }
}
Álvaro Agüero
  • 4,494
  • 1
  • 42
  • 39