12

Here's the problem: When I have an activity running in the background, and I switch locales, and I switch back to the application, everything updates... EXCEPT checkboxes and radio buttons that have an "android:id" attribute set.

If the checkboxes and radio buttons don't have the "android:id" attribute, then they update OK. Other fields don't have this problem, whether they have an "android:id" attribute or not.

What is the best way to make sure everything in my running activity is updated whenever the locale is changed?

Steps to reproduce:

1) Create a "Hello, Android" project in Eclipse. 2) In the main layout, define two checkboxes:

<CheckBox android:text="@string/checkbox" android:id="@+id/CheckBox01" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
<CheckBox android:text="@string/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>

3) Create two strings.xml: one under "values" and one under "values-es".

4) Create the following string under "values":

<string name="checkbox">English</string>

5) Create the following string under "values-es"

<string name="checkbox">español</string>

6) Set device to “English”

7) Run the application on the emulator or any device (tested on HTC G1).

8) Observe. Both checkboxes say “English”.

9) Press “Home” to return to the menu and leave the application running in the background.

10) Go to the settings. Switch the language to “español"

11) Press and hold “Home”. Return to the application.

Expected result:

Both checkboxes say “español”

Actual result:

First checkbox says “English”

Second checkbox says “español”

It appears that the checkbox with an “android:id” attribute is not updating as it should. The checkbox without the “android:id” attribute is working as expected.

Kevin
  • 121
  • 1
  • 3
  • 1
    A patch to fix this behavior have been merged to master branch. Refer to https://android-review.googlesource.com/#/c/67850/ – vic Jan 08 '14 at 06:04

4 Answers4

9

The cause of the problem is that CompoundButton.onSaveInstanceState() calls setFreezesText(true) and thus saves&restores the text.

A simple solution is using a subclass like this:

public class CheckBoxNoPersistentText extends CheckBox {

    public CheckBoxNoPersistentText(final Context context) {
        super(context);
    }

    public CheckBoxNoPersistentText(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    public CheckBoxNoPersistentText(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void onRestoreInstanceState(final Parcelable state) {

        final CharSequence text = getText(); // the text has been resolved anew

        super.onRestoreInstanceState(state); // this restores the old text

        setText(text); // this overwrites the restored text with the newly resolved text

    }
}
5agado
  • 2,444
  • 2
  • 21
  • 30
aleubner
  • 99
  • 1
  • 1
5

That is a fascinating bug. I can reproduce it on my Nexus One.

It seems to be in the default implementation of onSaveInstanceState(). If you override that to be a no-op (do not chain to the superclass), the problem goes away.

The default onSaveInstanceState() is supposed to handle stuff like the checkbox state, but they must have botched that and are saving the text, too.

So, you have a couple of workarounds:

  1. Override onSaveInstanceState() and do not chain to the superclass. This, however, eliminates any automatic state-saving you would ordinarily get.
  2. In onRestoreInstanceState() (...I think...), after chaining to the superclass, call setText() on your affected widgets with the proper string resource, to reset it back to the right value.

I will try to follow up on this more tomorrow when I get a chance. I want to check the source code and probably file this as an issue.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Well, I cannot reproduce this problem on Android 2.3 in the emulator, and I do not see in the source code how this could be occurring. For the moment, I will assume that this problem is fixed in Android 2.3. My workarounds above should still be valid. – CommonsWare Dec 22 '10 at 19:49
  • I also noticed that overriding the onSaveInstanceState() also "fixed" the problem, although it does have the bad side effect of disabling state-saving. I like your suggestion of calling setText() on the affected widgets. – Kevin Dec 23 '10 at 21:21
  • I am still able to reproduce this in the Android 2.3 emulator, though. – Kevin Dec 23 '10 at 21:21
  • @Kevin: Really? I tried to reproduce it in the Android 2.3 emulator and failed. Is there a way you can ZIP up your project source code and post it somewhere, putting the link here in a comment? I'll feel more comfortable if you and I are working off the same code, and since yours seems to fail more regularly, I'd recommend using it. – CommonsWare Dec 23 '10 at 21:24
  • @CommonsWare: Could you try out the project attached here? http://code.google.com/p/android/issues/detail?id=13252 Thanks for taking a look into this! – Kevin Dec 23 '10 at 21:46
  • @Kevin: I'll try to take a look at it in the next few days. Thanks for posting it! – CommonsWare Dec 24 '10 at 07:29
  • @Kevin: Yes, I am now able to reproduce the problem on the Android 2.3 emulator. – CommonsWare Dec 25 '10 at 22:25
  • Google did not fix it in ICS neither in JB – Blackbelt Jan 23 '13 at 16:22
  • @CommonsWare: Hi, request your kind help with [this](https://stackoverflow.com/q/52187959/3287204). – Yash Sampat Sep 07 '18 at 15:01
0

This 2 years old ticket proposes a workaround of not using the android:id so I fixed this issue by using a similar layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- KEEP THIS ALWAYS THE FIRST because it dosen't have
        an android:id as a workaround of this bug
        https://code.google.com/p/android/issues/detail?id=13252
        -->
    <RadioButton xmlns:android="http://schemas.android.com/apk/res/android" />

    <!-- other elements -->

</RelativeLayout>

So now to get the RadioButton I use something like this:

private RadioButton getButton(RelativeLayout layout) {
    RadioButton button = null;
    if (layout.getChildCount() != 0) {
        button = (RadioButton) layout.getChildAt(0);
    }
    return button;
}

So I can set the properties programmatically.

John L. Jegutanis
  • 802
  • 1
  • 10
  • 21
0

If some of these are in memory they will not change. If you reboot the phone, reinstall the application or at least completely kill the app it will work fine.

Manfred Moser
  • 29,539
  • 13
  • 92
  • 123
  • AFAIK, locale changes are configuration changes, and therefore the strings should be replaced when the activity is destroyed and recreated. – CommonsWare Dec 21 '10 at 21:45
  • well... I have seen the same behaviour that some string hang around though. There might be some application context loading or caching hanging around. I just know that an app redeploy or restart always fixes it. – Manfred Moser Dec 21 '10 at 21:49
  • Yes, I tried with some other elements such as TextView and the strings are all updated correctly whether they have an ID or not. It's just checkboxes and radio buttons that seem to have an issue. – Kevin Dec 23 '10 at 21:24