- MVVM Architecture & LiveData, ViewModel, LifeCycle Components
- Why am I here
- Let’s get started
- Downloaded, Good to Go 👍🏻
- We will start with LiveData
- ViewModel
- Handling Life Cycle
- Model-View-ViewModel
- DataModel
- ViewModel
- Test Project
- Организация простой архитектуры в андроид-приложении со связкой ViewModel+LiveData, Retrofit+Coroutines
- Настройка проекта
- Зависимости
- Манифест
- Настройка ретрофита
- Api интерфейс
- ViewModel
- Ивенты
- LiveData Clean Code using MVVM and Android Architecture Components
- Views aren’t easy to test, as it contains android related frameworks.
- View Model should not have any reference of view.
- LiveData is a observer wrapper over a model data that is lifecycle aware
- Using LiveData with Domain Layer or Repository Layer
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.
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.
Источник
Организация простой архитектуры в андроид-приложении со связкой ViewModel+LiveData, Retrofit+Coroutines
Без долгих вступлений расскажу, как можно быстро и просто организовать удобную архитекруту вашего приложения. Материал будет полезен тем, кто не очень хорошо знаком с mvvm-паттерном и котлиновскими корутинами.
Итак, у нас стоит простая задача: получить и обработать сетевой запрос, вывести результат во вью.
Наши действия: из активити (фрагмента) вызываем нужный метод ViewModel -> ViewModel обращается к ретрофитовской ручке, выполняя запрос через корутины -> ответ сетится в лайвдату в виде ивента -> в активити получая ивент передаём данные во вью.
Настройка проекта
Зависимости
Манифест
Настройка ретрофита
Создаем котлиновский объект NetworkService. Это будет наш сетевой клиент — синглтон
UPD синглтон используем для простоты понимания. В комментариях указали, что правильнее использовать инверсию контроля, но это отдельная тема
Api интерфейс
Используем замоканные запросы к фэйковому сервису.
Приостановим веселье, здесь начинается магия корутин.
Помечаем наши функции ключевым словом suspend fun . .
Ретрофит научился работать с котлиновскими suspend функциями с версии 2.6.0, теперь он напрямую выполняет сетевой запрос и возвращает объект с данными:
ResponseWrapper — это простой класс-обертка для наших сетевых запросов:
ViewModel
Создаем абстрактный класс BaseViewModel, от которого будут наследоваться все наши ViewModel. Здесь остановимся подробнее:
Ивенты
Крутое решение от Гугла — оборачивать дата классы в класс-обертку Event, в котором у нас может быть несколько состояний, как правило это LOADING, SUCCESS и ERROR.
Вот как это работает. Во время сетевого запроса мы создаем ивент со статусом LOADING. Ждем ответа от сервера и потом оборачиваем данные ивентом и отправляем его с заданным статусом дальше. Во вью проверяем тип ивента и в зависимости от состояния устанавливаем разные состояния для вью. Примерно на такой-же философии строится архитектурный паттерн MVI
Источник
LiveData Clean Code using MVVM and Android Architecture Components
Jul 20, 2018 · 6 min read
This article will talk about things related to every android developer heart : handling lifecycle events, making code cleaner. Remember those days where activity used to hundred or thousand of lines, you most probably have faced this challenges. Perhaps this would be no surprise we’ve all looked at the mess and felt the relief of our messy activity work.
For those familiar with Uncle Bob, Clean Architecture is no stranger. It’s a set of architectural guidelines based on SOLID principles.
This principles helps to achieve: testability, separation of concerns, modularity, among some other good practices.
In ou r simple priority order, developer wants there business as well as UI logic should be unit tested.
Views aren’t easy to test, as it contains android related frameworks.
Views should be dumb and implement Passive View pattern. Passive View pattern is a concept that UI logic should be minimum. Coming to Single responsibility principle view have responsibility of rendering. It should display the view state currently the user is.
For example: If we are implementing login screen, you should not write validation logic inside UI, it should be responsibility of the presentation layer.
As View has context its a gateway for android related frameworks too.We should try not to put conditional logic inside our view, as views does not support unit testing. We can test UI using Roboelectric , Instrumentation testing or Espresso.
The Presentation layer should be responsible of having business logic (like input validation), communication to data layer and provide data for UI rendering. Presentation layer (ViewModel or Presenter) does not use android framework it should be agnostic, so you can encapsulate all logic and that makes it testable. We can use JVM unit testing here. It should not have any direct dependency of view.
In this article I’m following MVVM architectural pattern. The main pillars of this pattern are :
- The View — that informs the ViewModel about the user’s actions
- The ViewModel- presentation layer, having UI logic and taking to data model.
- The DataModel — abstracts the data source. It can have both remote and local data. The ViewModel works with the DataModel to get and save the data.
View Model should not have any reference of view.
We have issue like what should be scope of view model on configuration change, will it die if activity dies. Suppose we have long running operations in background and if configurations changes and viewmodel has reference to view it might lead to memory leaks and null pointer exceptions.
Recently during Google I/O, Google introduced Livedata and ViewModel as part of architecture components. Android Architecture Components is a new collection of libraries to help developers manage lifecycle issues, write modular code and provide great user experience.
We can take advantage of lifecycle components. Our view activity or fragment have a lifecycle owner. Using this lifecycle components we can make our presentation layer aware of this. Our ViewModel can now outlive configuration changes (such as rotation) and survive as it is persisted. If view is resuming after configuration change it would get back the previous ViewModel, this can help to achieve view state consistency.
There is also AndroidViewModel which comes with context, but be aware of it using as it cannot be unit tested and polluting with android frameworks. It’s somewhat defeat the purpose of separation of concern.
LiveData is a observer wrapper over a model data that is lifecycle aware
ViewModel exposes livedata that view observes it. Whenever livedata changes view gets notified and it could re-render itself.
You can use either setValue() (used in ui thread) or postValue() (used in background thread) when you want to emit item from livedata.
LiveData knows about your activity state because it has lifecycle owner which we pass in observe parameter, so livedata will not trigger change method if view is destroyed.
- Activity i.e. View is observing to live data exposed by ViewModel.
- Since livedata is present inside View Model it’s retains on configuration change.
- ViewModel does not have activity reference so there would be no memory leaks, no need to handle lifecycle events such as we do with RxJava unsubscribe observable either on onStop or onDestroy.
Using LiveData with Domain Layer or Repository Layer
Following with separation of concern principle we should have a separate layer for data i.e. repository, its a single source of contact for getting data. You can have multiple repositories depends on use cases.
Repository can have instances of :
- Remote i.e. network
- Database
- Cache or Shared Preferences.
Flow of information is unidirectional.
You could also have a interactor present which could have some core logic and that exposes livedata to viewmodel which makes interactor also lifecycle aware.
The benefit using livedata in repository is that your repository layer also becomes lifecycle aware.
Following MVVM principle viewmodel should have business logic. Suppose we make an api call if it fails viewmodel should ideally have logic for error displays. For observing livedata we need life cycle owner. ViewModel doesn’t have lifecycle owner, to observe livedata inside viewmodel we can bind that bind that livedata using databinding. As livedata supports data binding we can leverage that.
Livedata is also helpful for navigation, you don’t need to create interface (called as navigator) that needs to be implemented by view and injected in viewmodel.
ViewModel would expose livedata suppose some itemClick livedata and view would observe to it. This way you can expose livedata events that viewmodel wants view to handle it.
For communication between viewmodel and repository we use Transformations. You use transformation methods to carry information across the observer’s lifecycle.
Transformations has map and switchMap operators similar to RxJava which can converts on livedata to different one.
You can also use Mediator livedata to create your own custom operators. MediatorLiveData is used for observing multiple livedata sources and perform on there changes.
If using retrofit I’ve created a wrapper above it where you can achieve onSubscribe, onSuccess and onError if coming from RxJava background. I will add sample github repository link at the end.
Suppose activity needs to tell viewmodel to load data from api. In below snippet we expose loadData livedata activity calls that livedata and viewmodel is listening to the change and calling the api and the response objected is binded to view.
You can write a binding adapter for updating the view
Even for folks using RxJava, can use RxJava in repository layer and expose livedata to viewmodel, which will benefit as its lifecycle aware.
Creates an Observable livedata stream from a ReactiveStreams publisher. SO you could use it to convert RxJava observables to livedata.
RxJava has very rich operators and threading. It also comes with some steep learning curve. RxJava and livedata both compliment each other, use RxJava in data layer where you can use complex operators and return livedata to viewmodel.
You can extend livedata for different use-cases. For example you can create LocationLiveData as singleton in your application and only emit values when some subscriber is active.
When extending live data we need to implement some methods.
- The onActive() method is called when the LiveData object has an active observer.
- The onInactive() method is called when the LiveData object doesn’t have any active observers.
- The setValue(T) method updates the value of the LiveData instance and notifies any active observers about the change
There is lot that can be done using livedata as its lifecycle aware.
In the end I would like to conclude that we got a cleaner code and separation of concerns for each layer using livedata. I have added sample app link for reference below.
Thanks for reading and if you like the article, remember to clap.
Источник