Android viewmodel lifecycle owner

MVVM Architecture & LiveData, ViewModel, LifeCycle Components

Jan 3, 2018 · 8 min read

MVC, MVP and MVVM are some of the Architecture patterns used by developers around the world. Which one to use, depends upon the requirement and how comfortable is one with the architecture pattern. However you should try to use one, it helps to keep the code segregated, modularised, readable, decoupled and easier to test.

Since the android development started Google never came up with their own architecture until recently. Google has introduced android architecture components which includes Life cycles, ViewModel, Room and LiveData.

Why am I here

This Article will provide brief of MVVM Architecture, LiveData, ViewModel and Lifecycle components.

Let’s get started

Befo r e we start, I would recommend you to download a project from here. This Application displays list of news in a Recycler view and on click of any news item, detailed news will be opened in a WebView. You can also refer screenshots from here. As we go through the article, we will be using pieces of code from this project to understand architecture pattern and components.

Downloaded, Good to Go 👍🏻

So Finally there is an architecture(MVVM) which follows the Single Responsibility Principle. Each component does single and unique Job, which is why it is recommended to write as many component classes as many needed. Before moving to MVVM Let’s understand Android components.

We will start with LiveData

LiveData is an observable holder class. It is like any other observer which implements Observer class, but LiveData is also linked with component (activity/Fragment/Service) life cycle. In case a component is destroyed, it will automatically stop observing the changes and release unused allocated memory which would help in avoiding memory leaks.

Using LiveData you consolidate your UI since observer would be triggering the UI changes if there is any change in data properties. We can wrap around an object to LiveData and start listening for data changes.

In the Above Example News object is being fetched by an api call and is wrapped inside LiveData. UI layer observes LiveData object changes. So on change of object properties, UI would be changed automatically. Also, it will save us the trouble of handling cases such as what happens if user kills activity in the middle of API call since it will stop listening to the changes as soon as activity is destroyed.

ViewModel

If you use a ViewModel, you would not have to worry about saving the data on configuration changes. In general, on configuration change activity is recreated and so does every other data retrieval. It can be an API call, db call or any other data related operation. ViewModel saves us all this trouble and keep the data alive until component is killed.

Let’s say we have an activity which displays result based upon searched query. Activity gets search query text from another component and then makes an API call to display results. In this case if user rotates device, there would be repetitive API call. If a ViewModel is used for any such cases then data would be saved automatically. ViewModel objects are automatically retained on configuration changes.

ViewModel objects are attached to component life cycle and only gets away when the component is destroyed. In case of Activity it would be in onDestroy() and in case of Fragment it would be in onDetach().

In the example, News object is wrapped inside NewsViewModel and same is used for observing data inside fragment.

Also, You should avoid keeping references of views in ViewModel , that might lead memory leaks since ViewModel does not get destroyed on configuration changes. However ViewModel won’t be retained on back press, if application is removed from recent or if system kills the activity. In such cases onSaveInstance method has to be implemented to retain the needed data.

Apart from this You can share data between two fragments using ViewModel. It can be done something like this.

Off course, You can do it using interfaces but that is a cumbersome way to handle communication. If you use ViewModel, Activity and Fragment would not have any clue of communication. They will be communicating through SharedViewModel. You can read more about it from here.

Читайте также:  Телевизор gazer tv32 hs2g hd smart tv android

Handling Life Cycle

This Architecture components comes with LifeCycle Observer. As name suggests you can create an observer which will bind to a component’s lifecycle.

In the below example SomeObserver is implementing LifecycleObserver class. SomeObserver is bound to an activity so it will follow activity’s lifecycle. As Activity’s onResume gets called, onResume of SomeObserver will also be called since it is linked to ON_RESUME event of Activity.

Use case: You want to fetch user’s fine location only if activity is visible. if not then coarse location. For this, In the observer class for onResume and onPause method you can switch the location update source from coarse to fine or vice-versa.

Fragments and Activities already implement the LifeCycleOwner interface in Support Library 26.1.0 and later. Before that you would have to extend LifeCycleFragment or LifeCycleActivity for fragment and activity correspondingly.

Also, You can make your own class Lifecycle Owner by implementing LifeCycleOwner class and mark the methods which you want to expose using LifecycleRegistry.

We are done with Architecture components. Let’s talk about MVVM Architecture now.

Model-View-ViewModel

DataModel

DataModel contains the data from different sources, can be API or can be from database . It is the Single entry point to your data. Most of the times datamodel contains API or DataBase Logic. DataModel fetches the data from required sources and present it to ViewModel. This layer also handles business logic so that latest and required data is exposed to the ViewModel.

ViewModel

This ViewModel is different from what we discussed above. This is term defined for MVVM Architecture.

ViewModel interacts with Data Model by an observable and It exposes only needed data for View Layer by an observable. Basically ViewModel does the same job for View, what Model does for ViewModel.

ViewModel prepares data for UI layer and keep it if needed, Any action on UI will be handled by ViewModel and any data changes will be observed by UI in View Layer. This helps to keep the UI and data Logic separated.

ViewModel exposes only relevant and needed data to the View. If we need 2 properties of an object, we will fetch those 2 properties, combine them into single object and then expose for View.

View is the UI interface , It can be an activity, fragment or a custom view. ViewModel prepares data for View, Binding of ViewModel to View is done in layout XML This is called Data binding of Layout Files.

To make the XML bindable, layout tag needs to be included in the XML. By Default a Binding class would be generated which will have references of all views and properties. if name of layout is activity_main, binding file would be ActivityMainBinding.

In layout XML file we can also include data object, with the help of which data can be populated to the views.

In the above example we have declared Article object and we are using this object to set the title in textview. Expressions within the layout are written in the attribute properties using the “ @<> » syntax.

However some times we need to write custom implementation for a property, Let’s say we are getting a Date as String from data object and want to format this date to another format, For such cases we can write our own custom methods annotating with BindingAdapter and passing the property name.

In the example i am using dateText property. Android does not know this property so we have to write a method which represents this property, now anywhere in the application you can use this tag and on run time it will call the BindingAdapter annotated method.

You can pass multiple properties for BindingAdapter method, making them optional or mandatory. You can read more about binding from here.

Test Project

Now let’s try to put all these pieces together and find out what is what in the sample project.

Источник

Android Architecture Components. Часть 2. Lifecycle

Как я уже упоминал в предыдущем материале, компонент Lifecycle призван упростить работу с жизненным циклом, а имено избежать калбеков с Activity/Fragment в наш компонент, который должен реагировать на события жизненого цикла. В этой статье, мы подробно разберем как он устроен и как с ним работать.

Сам компонент состоит из классов: Lifecycle, LifecycleActivity, LifecycleFragment, LifecycleService, ProcessLifecycleOwner, LifecycleRegistry. Интерфейсов: LifecycleOwner, LifecycleObserver, LifecycleRegistryOwner.

Читайте также:  Find more android apps

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 компонент.

Источник

Android Architecture Components. Часть 4. ViewModel

Компонент ViewModel — предназначен для хранения и управления данными, связанными с представлением, а заодно, избавить нас от проблемы, связанной с пересозданием активити во время таких операций, как переворот экрана и т.д. Не стоит его воспринимать, как замену onSaveInstanceState, поскольку, после того как система уничтожит нашу активити, к примеру, когда мы перейдем в другое приложение, ViewModel будет также уничтожен и не сохранит свое состояние. В целом же, компонент ViewModel можно охарактеризовать как синглтон с колекцией экземпляров классов ViewModel, который гарантирует, что не будет уничтожен пока есть активный экземпляр нашей активити и освободит ресурсы после ухода с нее (все немного сложнее, но выглядит как-то так). Стоит также отметить, что мы можем привязать любое количество ViewModel к нашей Activity(Fragment).

Компонент состоит из таких классов: ViewModel, AndroidViewModel, ViewModelProvider, ViewModelProviders, ViewModelStore, ViewModelStores. Разработчик будет работать только с ViewModel, AndroidViewModel и для получения истанца с ViewModelProviders, но для лучшего понимания компонента, мы поверхностно рассмотрим все классы.

Класс ViewModel, сам по себе представляет абстрактный класс, без абстрактных методов и с одним protected методом onCleared(). Для реализации собственного ViewModel, нам всего лишь необходимо унаследовать свой класс от ViewModel с конструктором без параметров и это все. Если же нам нужно очистить ресурсы, то необходимо переопределить метод onCleared(), который будет вызван когда ViewModel долго не доступна и должна быть уничтожена. Как пример, можно вспомнить предыдущую статью про LiveData, а конкретно о методе observeForever(Observer), который требует явной отписки, и как раз в методе onCleared() уместно ее реализовать. Стоит еще добавить, что во избежания утечки памяти, не нужно ссылаться напрямую на View или Context Activity из ViewModel. В целом, ViewModel должна быть абсолютно изолированная от представления данных. В таком случае появляется вопрос: А каким же образом нам уведомить представление (Activity/Fragment) об изменениях в наших данных? В этом случае на помощь нам приходит LiveData, все изменяемые данные мы должны хранить с помощью LiveData, если же нам необходимо, к примеру, показать и скрыть ProgressBar, мы можем создать MutableLiveData и хранить логику показать\скрыть в компоненте ViewModel. В общем это будет выглядеть так:

Читайте также:  Удаление яндекс диска с андроид

Для получения ссылки на наш экземпляр ViewModel мы должны воспользоваться ViewModelProviders:

Класс AndroidViewModel, являет собой расширение ViewModel, с единственным отличием — в конструкторе должен быть один параметр Application. Является довольно полезным расширением в случаях, когда нам нужно использовать Location Service или другой компонент, требующий Application Context. В работе с ним единственное отличие, это то что мы наследуем наш ViewModel от ApplicationViewModel. В Activity/Fragment инициализируем его точно также, как и обычный ViewModel.

Класс ViewModelProviders, являет собой четыре метода утилиты, которые, называются of и возвращают ViewModelProvider. Адаптированные для работы с Activity и Fragment, а также, с возможностью подставить свою реализацию ViewModelProvider.Factory, по умолчанию используется DefaultFactory, которая является вложенным классом в ViewModelProviders. Пока что других реализаций приведенных в пакете android.arch нет.

Класс ViewModelProvider, собственно говоря класс, который возвращает наш инстанс ViewModel. Не будем особо углубляться здесь, в общих чертах он являет роль посредника с ViewModelStore, который, хранит и поднимает наш интанс ViewModel и возвращает его с помощью метода get, который имеет две сигнатуры get(Class) и get(String key, Class modelClass). Смысл заключается в том, что мы можем привязать несколько ViewModel к нашему Activity/Fragment даже одного типа. Метод get возвращает их по String key, который по умолчанию формируется как: «android.arch.lifecycle.ViewModelProvider.DefaultKey:» + canonicalName

Класс ViewModelStores, являет собой фабричный метод, напомню: Фабричный метод — паттерн, который определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать, по факту, позволяет классу делегировать инстанцирование подклассам. На данный момент, в пакете android.arch присутствует как один интерфейс, так и один подкласс ViewModelStore.

Класс ViewModelStore, класс в котором и находится вся магия, состоит из методов put, get и clear. Про них не стоит беспокоится, поскольку работать напрямую мы с ними не должны, а с get и put и физически не можем, так как они объявлены как default (package-private), соответственно видны только внутри пакета. Но, для общего образования, рассмотрим устройство этого класса. Сам класс хранит в себе HashMap , методы get и put, соответственно, возвращают по ключу (по тому самому, который мы формируем во ViewModelProvider) или добавляют ViewModel. Метод clear(), вызовет метод onCleared() у всех наших ViewModel которые мы добавляли.

Для примера работы с ViewModel давайте реализуем небольшое приложение, позволяющее выбрать пользователю точку на карте, установить радиус и показывающее, находится человек в этом поле или нет. А также дающее возможность указать WiFi network, если пользователь подключен к нему, будем считать что он в радиусе, вне зависимости от физических координат.

Для начала создадим две LiveData для отслеживания локации и имени WiFi сети:

Теперь перейдем к ViewModel, поскольку у нас есть условие, которое зависит от полученных данных с двух LifeData, нам идеально подойдет MediatorLiveData как холдер самого значения, но поскольку перезапускать сервисы нам невыгодно, поэтому подпишемся к MediatorLiveData без привязки к жизненному циклу с помощью observeForever. В методе onCleared() реализуем отписку от него с помощью removeObserver. В свою же очередь LiveData будет уведомлять об изменении MutableLiveData, на которую и будет подписано наше представление.

И наше представление:

В общих чертах мы подписываемся на MutableLiveData, с помощью меnода getStatus() из нашего ViewModel. А также работаем с ним для инициализации и сохранения наших данных.

Здесь также добавлено несколько проверок, таких как RuntimePermission и проверка на состояние GPS. Как можно заметить, код в Activity получился довольно обширный, в случае сложного UI, гугл рекомендует посмотреть в сторону создания презентера(но это может быть излишество).

В примере также использовались такие библиотеки как:

Источник

Оцените статью