Комментарии 29
А просто обрабатывать onConfigurationChanged() не вариант?
Ну и еще обычно делают так.
В конструкторе AsynkTask:
this.activityRef = new WeakReference<SomeActivity>(activity);
В начале метода onPostExecute:
SomeActivity activity = activityRef.get();
if (activity==null) return;
Ну вынесите вы долгую операцию в сервис
зачем городить такое?
//waiting for our form
while (!(ctx.getCurrentActivity() instanceof AsmykPleaseWaitActivity)) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
return;
}
}
Опишите, пожалуйста, ваше предложение подробнее
Строго говоря, если разработчику нужны длительные операции в активити, фрагменте или вью — он нарушает SRP. Всё это нужно вынести в сервис, а в отображении только проверять состояние, нужна эта операция, работает или уже завершена.
Моя задача, реализация процесса регистрации:
1) Получаю от пользователя первую порцию данных
2) Выполняю шаг регистрации 1. Последовательно отправляется N различных запросов. Тут я хочу показывать пользователю, что именно сейчас программа делает
3) Получаю от пользователя вторую порцию данных
4) Выполняю шаг регистрации 2. Последовательно отправляется M различных запросов. Тут я хочу показывать пользователю, что именно сейчас программа делает
Как я должен это сделать при помощи сервисов?
Запросто.
1) Создаёте активность, которая проверяет состояние модели и отображает фрагмент соответствующий этапу регистрации.
2) Фрагмент спрашивает сервис работает ли его задача, и если работает отображает соответствующее уведомление, если нет — ожидает действий пользователя.
Всё. Состояния легко добавляются и однозначны. Кроме того, возможны любые перерывы в работе с приложением.
Да, я знаю что многие любят хранить состояние отображения в самом отображении. Это создаёт много проблем при поддержке.
В целом, создание ниток внутри пределов объекта и принадлежащих только создавшему объекту — жизнеспособная идея… в рамках агентного подхода. Но отображение на роль агента подходит плохо.
Кроме того, существуют лоадеры. Они продолжают работать пока фрагмент не был убит.
У фреймворка есть возможность запускать задачи UI при выполнении предусловий см https://mkabramyan.github.io/Asmyk/net/mabramyan/asmyk/core/AsmykUITask.html
Например вы можете выполнить какое либо UI задание из фоновой задачи/сервиса под конкретную Activity или при каких либо специфичных условиях (одно ограничение, проверка должна быть относительно быстрой).
Предусловия описываются в методе isApplicatble()
Запустить задачу вы можете вызвав метод runUITask экземпляра класса AsmykApplicationContext.
Если вы укажете параметр postpone=true, тогда задача будет выполнена если isApplicatble вернет true.
Если isApplicable вернет false задача будет отложена. Как только сменится текущая Activity проверка isApplicatble будет вызвана снова и так до тех пор пока isApplicatble не вернет true. Это позволяет однозначно выполнить специфичную UI задачу из фоновой операции.
Спасибо за вопрос, надеюсь у меня получилось описать понятно
После того как узнал о Moxy (https://github.com/Arello-Mobile/Moxy) вообще перестал беспокоиться о повороте экрана. В ней презентер спокойно переживает смену конфигурации и плюсом после пересоздания view применяет к нему все вызванные до поворота методы, что позволяет почти не париться о сохранении состояния.
public class AsmykApplicationContext extends Application {
...
private Activity currentActivity;
...
/**
* Internal method
*
* @param currentActivity
*/
protected synchronized void setCurrentActivity(AsmykCompatActivity currentActivity) {
this.currentActivity = currentActivity;
executeUITasks();
}
/**
* Get current activity
*
* @return
*/
public synchronized Activity getCurrentActivity() {
return currentActivity;
}
}
Не делайте так
+ «current Activity» вообще-то может быть больше одной штуки
Я вызываю setCurrentActivity в событии onResume. Каким образом их будет несколько?
Это одна из самых крутых утечек памяти из возможных на андроиде.
Я вызываю setCurrentActivity(null) на каждом onPause
Каким образом утечет память? См https://developer.android.com/guide/components/activities/activity-lifecycle.html
instantrun наверное на этом сильно поперхнется и не обновит ссылку
Почему?
Я вызываю setCurrentActivity в событии onResume. Каким образом их будет несколько?
Навскидку — multiwindow.
Я вызываю setCurrentActivity(null) на каждом onPause
Ну, к примеру, закрывается ActivityA и открывается ActivityB. Есть вероятность, что ActivityA.onPause() вызовется после ActivityB.onResume(). Тут получится что currentActivity null. Да, утечки памяти тут не будет, но все же нехорошо хранить ссылки на активити в контексте процесса.
Почему?
Ну тут наверное андроид студия показывает предупреждение
«Do not place Android context classes in static fields; this is a memory leak and also breaks Instant Run.» не так ли?
2) Где вы нашли статическое поле?
Навскидку — multiwindow.
См жизненный цикл multiwindow https://developer.android.com/guide/topics/ui/multi-window.html?hl=ru
Фреймворк не будет лагать в таком режиме. Просто UI задачи предназанченные для специфичной Activity будут выполняться только тогда, когда Activity будет реально актинвной. ИМХО случай довольно редкий, к тому же не вызовет ошибок. Помечу, эту особенность в Javadoc-е
но все же нехорошо хранить ссылки на активити в контексте процесса.
Почему?
Хорошо, мне ответить нечего больше :-) Основная моя идея что для контроля жизненного цикла активити и фрагментов лучше использовать предназначенные для этого стандартные компоненты, такие как лоадеры или setretaininstance когда надо. Если процесс не принадлежит одной активити то только тогда следует использовать что-то внешнее, например сервисы. Использовать максимально возможный scope — application/process можно, но только если понимаешь что делаешь. Из возможных проблем — wakelocks, doze mode, или неправильное понимание жизненного цикла фрагментов.
<activity
android:configChanges="keyboardHidden|orientation|screenSize"
...
/>
так не пробовал никто?
Поворот экрана во время выполнения долговременной операции