Проблема локализации Android: не все элементы в макете обновляются правильно при переключении локалей

Здесь проблема: когда у меня есть работа, работающая в фоновом режиме, и я переключаю локали, и я возвращаюсь к приложению, все обновляет... Исключает флажки и переключатели с атрибутом "android: id" .

Если флажки и переключатели не имеют атрибута "android: id" , они обновляют ОК. Другие поля не имеют этой проблемы, имеют ли они атрибут "android: id" или нет.

Каков наилучший способ убедиться, что все в моем текущем действии обновляется всякий раз, когда изменяется локаль?

Шаги для воспроизведения:

1) Создайте проект "Hello, Android" в Eclipse. 2) В главном макете определите два флажка:

<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) Создайте два strings.xml: один под "значениями" и один под "values-es".

4) Создайте следующую строку под "значениями":

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

5) Создайте следующую строку под "values-es"

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

6) Установите устройство на "английский"

7) Запустите приложение на эмуляторе или на любом устройстве (протестировано на HTC G1).

8) Соблюдайте. Оба флажка говорят "английский".

9) Нажмите "Домой", чтобы вернуться в меню и оставить приложение в фоновом режиме.

10) Перейдите к настройкам. Переключите язык на "español"

11) Нажмите и удерживайте "Домой". Вернитесь к приложению.

Ожидаемый результат:

Оба флажка говорят "español"

Фактический результат:

Первый флажок говорит "Английский"

Второй флажок говорит "español"

Похоже, что флажок с атрибутом "android: id" не обновляется, как следует. Флажок без атрибута "android: id" работает как ожидалось.

Ответ 1

Причиной проблемы является то, что CompoundButton.onSaveInstanceState() вызывает setFreezesText(true) и, таким образом, сохраняет и восстанавливает текст.

Простое решение использует подкласс следующим образом:

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

    }
}

Ответ 2

Это увлекательная ошибка. Я могу воспроизвести его на своем Nexus One.

Кажется, что в реализации по умолчанию onSaveInstanceState() используется по умолчанию. Если вы переопределите это как no-op (не привязывайтесь к суперклассу), проблема исчезнет.

Предполагается, что по умолчанию onSaveInstanceState() обрабатываются такие вещи, как состояние флажка, но они, должно быть, портили это и также сохраняют текст.

Итак, у вас есть несколько обходных решений:

  • Переопределить onSaveInstanceState() и не привязывать к суперклассу. Это, однако, устраняет автоматическое сохранение состояния, которое вы обычно получили.
  • В onRestoreInstanceState() (... я думаю...), после привязки к суперклассу, вызовите setText() на ваших затронутых виджетах с соответствующим строковым ресурсом, до reset верните его в нужное значение.

Я постараюсь продолжить это завтра, когда у меня появится шанс. Я хочу проверить исходный код и, возможно, указать это как проблему.

Ответ 3

Если некоторые из них находятся в памяти, они не изменятся. Если вы перезагрузите телефон, переустановите приложение или, по крайней мере, полностью убейте приложение, оно будет работать нормально.

Ответ 4

Этот 2-летний билет предлагает обходное решение, не использующее android: id, поэтому я исправил эту проблему, используя аналогичный макет:

<?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>

Итак, теперь, чтобы получить RadioButton, я использую что-то вроде этого:

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

Поэтому я могу программно установить свойства.