TextView иногда теряет содержимое при изменении конфигурации или кнопке «Домой»

TextView медленно заполняется текстом, поступающим из фонового сервиса. Я переопределил методы onSaveInstanceState() и onRestoreInstanceState() в MainActivity и добавил атрибут android:freezesText = "true" к TextView в макете. В большинстве случаев содержимое TextView сохраняется при повороте устройства или сворачивании приложения, нажатии кнопки «Домой» и запуске другого приложения. Однако время от времени содержимое теряется. Поскольку она медленно собирается фоновой службой, ее нелегко восстановить, и ценная информация теряется.

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

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    static private boolean firstRun = true;

    private final BroadcastReceiver receiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                String newPost = bundle.getString(MyService.POST);
                textView.append((new Date()).toString().substring(11, 19) + " " + newPost + "\n");
                // Delete 250 leading chars if too many
                Editable ed = textView.getEditableText();
                int len = ed.length();
                if ( len > 5000 ) ed.delete(0, 250);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.idTextView);
        if ( firstRun ) {
            firstRun = false;
            Intent intent = new Intent(this, MyService.class);
            startService(intent);
        }
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle  savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putCharSequence("TEXTVIEW", textView.getText());
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        CharSequence viewContents = savedInstanceState.getCharSequence("TEXTVIEW");
        textView.setText(viewContents);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceiver(receiver, new IntentFilter(MyService.NOTIFICATION));
    }
}

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

РЕДАКТИРОВАТЬ: Я добавил атрибут android:configChanges в Activity в манифесте. onCreate () теперь вызывается только один раз. Тем не менее, содержимое TextView иногда теряется из-за приложения начать сначала. Это происходит только при перерисовке приложения, при реконфигурации или при переводе его на передний план. Почему перезапускается? Logcat в Android Studio сообщает об отсутствии проблем.

Попробуйте добавить onPause() и вставить вызов unregisterReceiver(receiver).

Graziano 22.03.2022 10:21

Спасибо Грациано за это предложение. Не могли бы вы объяснить, как это влияет на содержимое TextView, когда устройство поворачивается или приложение скрыто другим? Как указано в другом комментарии, проверить решение довольно сложно.

Kalle Svensson 22.03.2022 10:46

В вашем коде есть 3 элемента, которые могут изменить ваш EditText во время вращения: BroadcastReceiver, атрибут android:freezesText = "true" и методы onSave/RestoreInstanceState. Мое предложение состоит в том, чтобы остановить первое (здесь мое предыдущее предложение), но я предлагаю также удалить второе (атрибут freezesText), чтобы оставить bunden и честь задачи onSave/RestoreInstanceState.

Graziano 22.03.2022 11:40

@Graziano Хорошо, легко удалить freezesText и добавить unregisterReceiver. Я могу попробовать. Но, честно говоря, получатель только добавляет больше текста, и я думаю, что freezesText ничего не делает, потому что я никогда не вызываю onSaveInstanceState и onRestoreInstanceState в TextView. Но опять же, я понятия не имею, почему/когда это происходит, поэтому это очень сложно проверить. Я никогда не буду уверен, что это решено.

Kalle Svensson 22.03.2022 12:22

@Graziano Добавление unregisterReceiver() оказалось совершенно необходимым, чтобы избежать утечки памяти, но оно не решило исчезающий текст. Я считаю, что onRestoreInstanceState() не вызывается в некоторых случаях, но я не знаю, когда и почему. Потеря текста в TextView происходит редко, но бывает. Я также добавил onRestoreInstanceState() к onCreate(), но это не помогло.

Kalle Svensson 28.03.2022 11:37
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
5
89
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

вы используете общие настройки

Для градиента

implementation 'com.google.code.gson:gson:2.8.8'

Инициализировать общие настройки

SharedPreferences  mPrefs = getPreferences(MODE_PRIVATE);

Сохранить данные или любой объект и класс

MyObject myObject = new MyObject;
Editor prefsEditor = mPrefs.edit();
Gson gson = new Gson();
String json = gson.toJson(myObject);
prefsEditor.putString("MyObject", json);
prefsEditor.commit();

Получить данные

Gson gson = new Gson();
String json = mPrefs.getString("MyObject", "");
MyObject obj = gson.fromJson(json, MyObject.class);

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

Kalle Svensson 22.03.2022 09:20

проверьте также Bundle, переданный в качестве аргумента методу onCreate

@Override
protected void onCreate(Bundle savedInstanceState) {
    ... your code
    checkInstanceState(savedInstanceState); // at the end after GUI init
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    checkInstanceState(savedInstanceState);
}


private void checkInstanceState(Bundle savedInstanceState) {
    if (savedInstanceState==null) return;
    CharSequence viewContents = savedInstanceState.getCharSequence("TEXTVIEW");
    textView.setText(viewContents);
}

Обратите внимание, что savedInstanceState не может быть нулевым в onRestoreInstanceState, см. документы. Я мог бы добавить восстановление TextView в onCreate, но onRestoreInstanceState приходит позже и переопределяет его. Проверить решение очень сложно, так как проблема возникает редко и я не знаю, как ее спровоцировать.

Kalle Svensson 22.03.2022 10:03
Ответ принят как подходящий

Потеря содержимого TextView происходит, когда Android время от времени уничтожает активность в фоновом режиме и воссоздает ее, когда приложение выводится на передний план. В этом случае в вызове onCreate()Bundle savedInstanceState есть null, и его нельзя использовать для восстановления TextView. Однако статические переменные в Activity сохраняются.

РЕШЕНИЕ: чтобы сохранить содержимое TextView в этом переходе уничтожения-создания, сохраните содержимое в статической переменной в onSaveInstanceState() и восстановите в onCreate(). В этом сценарии onRestoreInstanceState() никогда не вызывается и не может использоваться.

Я проверил это решение на устройстве с Android 7.0. Другие версии Android могут вести себя иначе. Жаль, что Android так плохо документирован.

Другие вопросы по теме