Урок 1. Lifecycle
В этом уроке рассмотрим возможности Lifecycle. Как подписаться на его события. Как узнать текущее состояние Activity.
Полный список уроков курса:
Довольно часто часть логики приложения завязана на жизненный цикл Activity. Мы включаем что-либо в методах onStart или onResume и выключаем в onPause или onStop.
У нас есть какой-то класс для работы с сервером. Он должен взаимодействовать с сервером, пока Activity открыто. Соответственно, мы будем подключать его к серверу при показе Activity и отключать при скрытии Activity.
Метод connect используется для подключения к серверу, disconnect — для отключения.
Вызываем эти методы в onStart и onStop в Activity.
Теперь MyServer будет подключен пока Activity видимо на экране.
Это вполне классическая, часто используемая схема. И в простом примере все выглядит неплохо. Но в сложных приложениях содержание методов onStart, onStop и пр. может состоять из нескольких десятков строк и быть достаточно запутанным. Гугл рекомендует выносить эту логику из Activity. Давайте посмотрим, как это можно сделать.
Lifecycle
У Activity есть метод getLifecycle, который возвращает объект Lifecycle. На этот объект можно подписать слушателей, которые будут получать уведомления при смене lifecycle-состояния Activity.
Activity и фрагменты в Support Library, начиная с версии 26.1.0 реализуют интерфейс LifecycleOwner. Именно этот интерфейс и добавляет им метод getLifecycle.
Т.е. у вас должна быть такая строка в build.gradle файле модуля, в секции dependencies
Либо используйте более свежую версию.
В нашем примере слушателем будет MyServer. Чтобы иметь возможность подписаться на Lifecycle, он должен наследовать интерфейс LifecycleObserver.
Обратите внимание, что интерфейс LifecycleObserver пустой. В нем нет кучи методов типа onStart, onStop и т.п. Мы просто помечаем в классе MyServer его же собственные методы аннотацией OnLifecycleEvent и указываем, при каком lifecycle-событии метод должен быть вызван.
В нашем примере, мы указываем, что метод connect должен вызываться в момент onStart, а метод disconnect — в момент onStop.
Осталось подписать экземпляр MyServer на Lifecycle.
В Activity методом getLifecycle получаем Lifecycle, и методом addObserver подписываем myServer.
А методы onStart и onStop в Activity нам больше не нужны, их можно удалить.
Теперь, при переходе Activity из состояния CREATED в состояние STARTED, его объект Lifecycle вызовет метод myServer.connect. А при переходе из STARTED в CREATED — Lifecycle вызовет myServer disconnect.
При этом в Acivity это потребовало от нас минимум кода — только подписать myServer на Lifecycle. Все остальное решает сам MyServer.
На схеме ниже вы можете увидеть какие состояние проходит Activity и какие события при этом вызываются.
Ничего нового тут для нас нет, все это азы Android. Тут вы можете видеть состояния и события. Они связаны очень просто — при переходе между состояниями происходят события.
Эти события мы указывали в аннотациях OnLifecycleEvent к методам объекта MyServer.
Полный список событий можно посмотреть в документации.
Отписаться от Lifecycle можно методом removeObserver.
Вы можете использовать событие ON_ANY для получения всех событий в одном методе
В этом случае все события будут вызывать этот метод.
Используйте входящий параметр event, чтобы определить, какое именно событие произошло
Состояние
Если вы хотите узнать текущее состояние Activity, то у его объекта Lifecycle есть метод getCurrentState:
Полный список состояний можно посмотреть в документации.
Также, вы можете проверить, что текущее состояние Activity не ниже определенного состояния.
Метод isAtLeast здесь проверяет, что состояние Activity не ниже, чем STARTED. Т.е. либо STARTED, либо RESUMED.
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Lifecycle — Aware Components
Architecture components are a set of android libraries that helps your app structure in a way that is testable, reusable, maintainable.
There are few lifecycle aware android architecture components:
- ViewModel: Helps to create, store and retrieve data and communicates with other components belonging to the same lifecycle.
- Lifecycle Owner: It’s an interface implemented by activity and fragment, to observe changes to the lifecycle of owners.
- LiveData: Allows observing changes in data across diff components in the same lifecycle.
View Model
ViewModel is a class that is responsible for preparing and managing data for Activities and Fragments. It also helps in communication between views.
It is the backbone of MVVM architecture. A ViewModel is always created with a scope and will be retained as long as the scope is alive. For example, we bind ViewModel scope with activity then until the activity is running we can change data and get updates of data.
It exposes data using LiveData or DataBinding.
MVVM architecture’s main players are Views, ViewModel, and DataModel. Activity and Fragments are views, they should contain view hierarchy.
Data manipulation, business logic, data fetch from server, database operation should never happen in the view layer. For this work we have ViewModel. It notifies views about diff events.
This is how we define ViewModel in our view class:
this refers to an instance of lifecycleOwner . That means ViewModel will be alive until lifecycleOwner is alive. That means when configuration changes happen like screen rotation, ViewModel will remain unaffected.
Let’s see the following diagram for lifecycle:
As you can see from the diagram when the screen is rotated activity and fragment instance is destroyed but ViewModel’s not.
Now when you rotate the device, it doesn’t save its state, and it losses the editText’s content.
Now do the same using ViewModel.
Now rotate the screen and you will see the data is preserved and there is no glitch in retaining data. So ViewModel helps us to handle configuration changes.
Use ViewModel to handle configuration changes
ViewModel is a good choice for storing and managing UI-related data. It allows quick access to data and helps you avoid prefetching data from the network or database when configuration changes happen like scree rotation and resizing of the app. ViewModel retains data. in memory which means it is. easy to access them.
Unlike saved instance states, ViewModels are destroyed during a system-initiated process death. This is why you should use ViewModel objects in combination with onSaveInstanceState() (or some other disk persistence), stashing identifiers in saved instance state to help view models reload the data after system death.
Use saved instance state as a backup for system-initiated process death.
Commonly, we want to share data between fragments. FOr example normal list of songs and then a detail or play view of that selected song. We can achieve that by view the model using their activity scope.
By this approach, both fragments are independent of each other. And independently using a shared ViewModel.
LiveData
LiveData is a data holder class that can be observed within a given lifecycle.
The observer will be notified about the modification of wrapped data inside livedata class.
An observer added with a Lifecycle will be automatically removed if the corresponding Lifecycle moves to Lifecycle.State.DESTROYED state.
This class is designed to hold individual data fields of ViewModel , but can also be used for sharing data between different modules in your application in a decoupled fashion.
Let’s understand it with an example of the Sleep tracker in HealthifyMe app:
In the red box, we have sleep goal(8h), and how much the user achieved (4h).
Step 1: Define LiveData object to store data and a method to observe that data in View class.
Step 2: Fetch data through API call in ViewModel class, and in onSuccess() save tha data in live Data object using sleepGoalFetchedLiveData.value = t
Step 3: Define viewModel object in activity. this refers to an instance of lifecycleOwner .
We are observing Data changes in activity so activity will be notified when live data has been set.
SleepGoalData class will contain sleep time and wake-up time. The goal will be the diff between these values.
Using the above code we will get our sleep goal and we will set UI.
Using the above example we can see how viewModel has been used to make API calls and data storing using live data and get the update inside our activity and fragment.
Now suppose the user wants to update the sleep goal. He will click on the edit button which was inside the red box of the above screenshot. User will enter in below Screen which is SleepGoalFragment .
Now because SleepGoalViewModel lifecycle is bound to activity lifeCycle and fragment is part of an activity, it will listen to all the changes happening in activity and vice versa.
Users can edit sleep time and wake time. Once after editing user click on the done button, we call saveSleepGoal API from SleepGoalViewModel.
Step 1: Define viewModel object with activity lifecycle.
Now on the done button click call saveGoal method of ViewModel.
Step 2: Call API to save data and set updated values in live data.
Because liveData is observed into activity and ViewModel lifecycle is bound to activity, even after fragment is closed, the activity will be notified for updated value and you will get. a callback inside getSleepGoal().
From the above example, we understood how liveData will help in data transition.
LifecycleOwner
It is an interface that is used by any class that has an android lifecycle. Both ViewModel and LiveData can bind to the lifecycle owner.
Many Android components and libraries require to subscribe, initialize, unsubscribe and stop the components. Failing to do that can lead to a memory leak.
Step 1: Implement LifecycleObserver to make lifeCycle aware component.
The listener will start observing as soon as the lifecycle owner is created and will stop once the lifecycle owner is destroyed. Now activity. doesn’t need to. handle all the state it will be done by life cycle owner once it is added.
You can query the current lifecycle state inside your LifecycleOwner such as activity using getLifecycle().getCurrentState()
Conclusion
As many actions in Android applications are lifecycle driven, using lifecycle-aware components that react to lifecycle status changes to perform actions helps produce better-organized, decoupled, and light-weight components, which in turn goes a long way to building a more maintainable and testable codebase.
Thank you for reading. 👏 I hope you’ve found this article helpful. Your claps are really appreciated to help others find this article 😃 .
Источник
Android Architecture Components. Часть 2. Lifecycle
Как я уже упоминал в предыдущем материале, компонент Lifecycle призван упростить работу с жизненным циклом, а имено избежать калбеков с Activity/Fragment в наш компонент, который должен реагировать на события жизненого цикла. В этой статье, мы подробно разберем как он устроен и как с ним работать.
Сам компонент состоит из классов: Lifecycle, LifecycleActivity, LifecycleFragment, LifecycleService, ProcessLifecycleOwner, LifecycleRegistry. Интерфейсов: LifecycleOwner, LifecycleObserver, LifecycleRegistryOwner.
Lifecycle — класс, который хранит информацию про состояние жизненного цикла и разрешает другим объектам отслеживать его c помощью реализации LifecycleObserver. Состоит из методов: addObserver(LifecycleObserver), removeObserver(LifecycleObserver) и getCurrentState(). Как понятно из названий для добавления подписчика, удаления и соответственно получения текущего состояния.
Для описания состояния есть два enum. Первый Events — который обозначает изменение цикла и второй State — который описывает текущее состояние.
Events — повторяет стадии жизненного цикла и состоит из ON_CREATE, ON_RESUME, ON_START, ON_PAUSE, ON_STOP, ON_DESTROY, а также ON_ANY который информирует про изменения состояния без привязки к конкретному этапу. Отслеживание изменений цикла происходит с помощью пометки метода в обсервере аннотацией OnLifecycleEvent, которому как параметр передается интересуещее нас событие.
State — состоит из следующих констант: INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED. Для получения состояния используеться метод getCurrentState() из Lifecycle. Также в Enum State реадизован метод itAtLeast(State), который отвечает на вопрос являтся State выше или равным от переданого как параметр.
Для работы с компонентом Lifecycle, нам нужно определить owner, то есть владельца жизненного цикла и observer, того кто на него будет подписан. У owner может быть любое количество подписчиков, также стоит отметить что observer будет проинформирован про изменение состояния, еще до того как у owner будет вызван метод super() на соответствующий метод жизненного цикла.
Owner должен реализовывать интерфейс LifecycleOwner, который содержит один метод getLifecycle(), который возвращает екземпляр класса холдера Lifecycle.
Observer должен реализовать интерфейс маркер LifecycleObserver.
Для самостоятельного обьявления кастомной Activity/Fragment, как owner-а, которые еще не поддерживают новый компонент и соответственно не имеют реализации Lifecycle, созданы: класс LifecycleRegistry и интерфейс LifecycleRegistryOwner.
Интерфейс LifecycleRegistryOwner, который в свою очередь расширяет интерфейс LifecycleOwner с единственым отличием в том что метод getLifecycle() возвращает LifecycleRegistry вместо Lifecycle.
Класс LifecycleRegistry, который являеться расширением Lifecycle и берет всю работу по поддержке на себя, нам лишь нужно создать его экземпляр.
Вот как выглядит реализация:
В пакете android.arch.lifecycle приведено 4 реализации owner: LifecycleActivity, LifecycleFragment, LifecycleService, ProcessLifecycleOwner.
LifecycleActivity — это FragmentActivity c реализацией LifecycleRegistryOwner. Является временным решением для упрощения работы и как сказано в документации будет пока Lifecycle не будет интегрирован с support library.
LifecycleFragment — это Fragment c пакета support.v4, который также как и в случае с LivecycleActivity реализовывает LifecycleRegistryOwner и является временным решением.
LifecycleService — это Service, который является также LifecycleOwner.
ProcessLifecycleOwner — это класс, который представляет Lifecycle всего процесса. Этот класс будет полезен если вам нужно отслеживать уход приложения в бэкграунд или возврат его на передний план.
Для того чтоб, связать owner и observer нужно у owner вызвать getLifecycle().addObserver(LifecycleObserver) Ниже я продемонстрирую работу всех этих классов. Для демонстрации, я создал класс SomeObserver, который будет логировать вызовы ON_CREATE и ON_STOP, я его буду использовать для всех видов owner-ов, поэтому для упрощения я добавил enum, константа с которого будет передаваться в конструктор и потом использоваться, чтоб отличить владельца по логам:
В целом же работа со всеми классами аналогичная, все что нам нужно это создать экземпляр обсервера и подписать его на Lifecycle, в моей реализации мы передаем наш Lifecycle в конструктор обсервера, подпиской занимаеться уже сам обсервер. Данный подход, является всего лишь делом вкуса и не более.
Листинг LifecycleService, он отрабатывает 5 секунд и завершается, его я запускаю из Application:
И для ProcessLifecycleOwner я решил расширить Application, как можно заметить ProcessLifecycleOwner сделан как singleton и являеться абсолютно самостоятельным компонентом:
Полный листинг вы можете посмотреть по линке: here
Также полезные ссылки: раз и два.
В следующей статье мы более подробно разберем LiveData компонент.
Источник