Intereting Posts
Android: Как изменить скорость воспроизведения музыки с помощью OpenSL ES Идентификаторы неработающих / длинных ресурсов Android не работают Возможно ли иметь несколько стилей внутри TextView? Создает ли родительский клик для всех дочерних элементов кликабель? Программирование с помощью SurfaceView и стратегии потоков для разработки игр ProgressBar.setProgressDrawable не работает для Android 2.3 SoapFault – faultcode: «1062» faultstring: «Способ доставки недоступен» Как остановить чрезмерное создание объектов на телефонах Samsung? GetFilesDir () возвращает null Android Developer Console – неправильный отпечаток пальца после выпуска с Android Studio Можете ли вы скрыть элемент в макете, например, прядильщика, в зависимости от активности? Почему не доступна библиотека поддержки Android версии 22? Что такое onCreate (Bundle savedInstanceState) Socket EADDRINUSE (адрес уже используется) Создайте точку доступа с помощью Nexus 7

Неисправность Backstack активности при разрушении деятельности

У меня есть два вида деятельности; Скажем, A и B. В activity A зарегистрирован приемник вещания, который прослушивает конкретное событие, которое завершит активность A. Я регистрирую приемник вещания в onCreate() и уничтожаю его в onDestroy() activity A

Для простоты в activity B есть одна button «Destroy Activity A». Когда пользователь нажимает button , activity A должна быть уничтожена.

Обычно все это работает бесперебойно без каких-либо проблем, но проблема возникает в следующих сценариях:

1) Предположим, что я нахожусь в activity B и я нажимаю клавишу «Домой», чтобы переместить приложение на задний план, а затем, если я использую другие ресурсоемкие приложения, система Android убьет мое приложение на свободную память. Затем, если я открою приложение из последних задач, activity B будет возобновлена, и будет onCreate() , onResume() т. Д. Теперь я нажимаю button чтобы уничтожить activity A , но активность A уже была уничтожена, поэтому activity A onCreate() , onResume() и так далее и не будут вызываться до тех пор, пока я не onResume() к activity A , нажав кнопку « back button . Таким образом, broadcast receiver не зарегистрирован для прослушивания события.

2) Такая же проблема возникает, когда пользователь выбрал «Не сохранять действия» из параметров разработчика в настройках устройства.

Я давно искал эту проблему, но я не могу найти правильный ответ. Каков наилучший способ справиться с этим сценарием? Это ошибка Android? Должно быть какое-то решение для этой проблемы.

Пожалуйста, помогите мне.

Solutions Collecting From Web of "Неисправность Backstack активности при разрушении деятельности"

Это не может быть исправлено при сохранении вашей текущей широковещательной логики.

Невозможно совершить убийство с помощью backsack, imo. Вы должны решительно рассмотреть возможность изменения логики вашей навигации.

Но если ваш проект большой, и время – проблема, и рефакторинг не может быть и речи, подход AJ работает, но вы упомянули, что у вас есть много действий, которые нужно убить, его решение становится очень сложным для реализации.

Я предлагаю следующее. Это может быть не лучшая идея, но я не могу думать о другом. Может быть, это может помочь.

У вас должно быть следующее:

  • Базовая деятельность для всех ваших действий.
  • Объект ArrayList<String> activitiesToKill activityToKill на уровне приложения. (Если вы не распространяете Application вы можете использовать его как статическую переменную

Сначала мы должны убедиться, что activitiesToKill не потерян, когда ОС убивает приложение в низкой памяти. В BaseActivity мы сохраняем список во время onSaveInstanceState и восстанавливаем его в onRestoreInstanceState

 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("activitiesToKill", activitiesToKill); } private void onRestoreInstanceState(Bundle state) { if (state != null) { activitiesToKill = (ArrayList<String>) state.getSerializable("activitiesToKill"); super.onRestoreInstanceState(state); } 

}

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

Логика следующая:

Допустим, у вас есть действия A, B, C, D и E

Из действия E нажмите кнопку, и вы хотите убить B и D

Когда вы нажимаете кнопку в E, вы добавляете имена B и D в объект activityToKill.

 activitiesToKill.add(B.class.getSimpleName() activitiesToKill.add(D.class.getSimpleName() 

В методе onCreate BaseActivity мы должны проверить,

 if(savedInstanceState != null) { //The activity is being restored. We check if the it is in the lest to Kill and we finish it if(activitiesToKill.contains(this.getClass().getSimpleName())) { activitiesToKill.remove(this.getClass().getSimpleName()) finish(); } } 

Обязательно удалите имя операции, если оно будет убито в ходе трансляции.

Так что в основном это то, что происходит в каждом сценарии.

Если приложение работает нормально, и вы нажимаете кнопку, трансляция отправляется, а B и D будут убиты. Обязательно удалите B и D из activitiesToKill

Если приложение было убито и восстановлено, вы нажмете кнопку, трансляция не будет иметь никакого эффекта, но вы добавили B и D в объект activityToKill. Поэтому, когда вы нажимаете «назад», действие создается, а значение savedInstanceState не равно null, действие завершено.

Этот подход считает, что деятельность E знает, какие действия она должна убить.

Если вы НЕ знаете, какие действия нужно убить с E, вам нужно немного изменить эту логику:

Вместо использования ArrayList используйте HashMap<String, bool>

Когда действие B будет создано, оно зарегистрирует его самостоятельно в hashmap:

 activitiesToKill.put(this.class.getSimpleName(), false) 

Затем из Activity E все, что вам нужно сделать, это установить все записи в true

Затем во время создания базового действия вы должны проверить, зарегистрировано ли это действие в ActivityToKill (hashmap содержит ключ) И логическое значение true вы его убиваете (не забудьте вернуть его в false или удалить ключ)

Это гарантирует, что каждый вид активности регистрируется в HashMap и Activity E, и не знает, какие действия нужно убить. И не забудьте удалить их, если трансляция убивает их.

Этот подход также гарантирует, что активность не будет убита при обычном открытии с намерением, поскольку в этом случае onSaveInstanceState будет иметь значение null в onCreate, поэтому ничего не произойдет.

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

Также обратите внимание, что вы можете использовать getName вместо getSimpleName, если у вас есть несколько действий с тем же именем, но с разными пучками.

Надеюсь, мои объяснения достаточно ясны, поскольку я написал это со своей головы, дайте мне знать, если какая-либо область не ясна.

Удачи

Если ваша Activity A была уничтожена самой ОС Android, тогда нет способа отслеживать.

Некоторые люди предложили отслеживать эту Activity A , перечислив событие в методе onDestroy но если ваша Activity убита системной ОС, тогда обратите внимание на то, что она не вызовет этот метод.

Я не знаю, можно ли с этим справиться «правильно».

На мой взгляд, нужно каким-то образом отметить действие A. Вы не можете использовать startActivityForResult() потому что вы получите результат до того, как onResume() т.е. пользовательский интерфейс уже завышен.

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

Вам нужно будет проверить этот флаг на свой onCreate() перед вызовом setContentView() , если флаг является истинным, просто закончите действие.

С информацией, которую вы предоставили, как насчет того, как вы зарегистрируете трансляцию в onCreate of Activity B после проверки, зарегистрирована ли она уже или нет. Если onDestroy Activity A был вызван в любом из описанных вами сценариев, тогда был бы вызван дерегистр Broadcast. Таким образом, в этом случае вы можете зарегистрировать свою трансляцию в onCreate of Activity B, чтобы вы могли ее слушать, даже если у вас есть только активность B в вашей задней части.

Считаете ли вы использование липкой трансляции ? Также вы можете зарегистрировать получателя на уровне приложения (в манифесте) и прослушать это событие независимо от состояния Activity A

Но, как уже говорилось, Юсеф , убийство действий из задней части стопы – не правильный подход. Вы должны решительно рассмотреть возможность изменения логики вашей навигации.

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

В вашем примере (если я понимаю, что вы пытаетесь сделать) вам нужно перейти к чему-то под A – скажем, Activity Z , и стек выглядит следующим образом: ZA-[B] . Есть нормальный ход событий, когда вы отбиваетесь back и он переносит вас в A , затем после другого удара – на Z но в определенном случае (например, нажав кнопку) вы хотите вернуться к Z обход A – это классический Чтобы использовать FLAG_ACTIVITY_CLEAR_TOP и запустить Z явно :

 Intent intent = new Intent(this, ActivityZ.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); 

Это закончит как B и A , и довести намерение до Z Вероятно, вам также понадобится флаг FLAG_ACTIVITY_SINGLE_TOP , обратите пристальное внимание на описание FLAG_ACTIVITY_CLEAR_TOP , вы должны подумать об обмане.

Многие решения пришли мне на ум, но поскольку вы не предоставили много информации о своем приложении, я думаю, что это должно работать в целом.

Вместо того, чтобы запускать трансляцию, чтобы убить Activity A, просто выполните следующий код, когда кнопка «Kill Activity A» нажата в Activity B.

  Intent intent = new Intent(getApplicationContext(), ActivityA.class); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); intent.putExtra("EXIT", true); startActivity(intent); 

Добавьте следующий код в действие A

 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); if (intent.getBooleanExtra("EXIT", false)) { finish(); } } protected void onCreate(Bundle savedInstanceState) { //Ideally, there should not be anything before this super.onCreate(savedInstanceState); if(getIntent().getBooleanExtra("EXIT", false)){ finish(); return; } 

В манифесте установлен режим запуска «singleTop» для активности A.

 <activity android:name=".ActivityA" ... android:launchMode="singleTop" /> 

Это будет иметь следующие последствия:

  • Если операция А уже запущена, она будет перенесена в начало стека действий и закончена, удалив ее из стека.
  • Если Activity A был уничтожен, но все еще присутствует в стеке действий (который будет запущен при нажатии кнопки «Назад»), он будет запущен, доведен до конца и закончен, тем самым удалив его из стека действий.
  • Если активность A уже была уничтожена и не присутствует в стеке действий, и вы все равно нажимаете кнопку «Удалить действие A», она будет запущена, доведена до конца и закончена.

Как правило, вы не должны видеть мерцания.

Основываясь на этой идее, вы можете создать более эффективное решение для своего конкретного приложения. Например, вы можете использовать FLAG_ACTIVITY_CLEAR_TOP и завершить действие A в onBackPressed () для операции B.

1) Вы можете хранить информацию об активности для уничтожения в каком-либо статическом классе. Если может быть мало случаев, вы можете сохранить массив значений int , например:

 static final int ACTIVITY_DESTROY_FLAG_ACTIVITY_A = 1 static final int ACTIVITY_DESTROY_FLAG_ACTIVITY_B = 2 

В onResume активности проверьте, следует ли ее уничтожить. Для Activity_A это может выглядеть так:

 if (StaticClass.activityArray.contains(ACTIVITY_DESTROY_FLAG_ACTIVITY_A)) { finish(); } 

2) Заблаговременно к вашему механизму intent.putExtra("activity", Activity_A.this) радиопередач вы можете поместить активность в Intent путем intent.putExtra("activity", Activity_A.this) и отправить его с трансляцией из onCreate of Activity_A . В Activity_B зарегистрируйте широковещательный приемник и в кнопках onClick call ((Activity) intent.getExtras().get("activity")).finish() . Ну, еще один приемник – вы потратите на это ресурсы?