Right now I am trying to create a process, where I want to insert data in table and some observers will get notified and able to edit the data upon their interest. Below is a rough idea on how to do it. Can anyone please suggest the model/arch how I can achieve this?
Follow this tutorial on Room, ViewModel, and LiveData.
Room is a SQL database abstraction which can expose its data through LiveData. ViewModel is a class that holds data for the UI and survives configuration changes. LiveData is an observable container for data that is aware of the android lifecycle so you don't have to manage it in the lifecycle callbacks.
Basically, you create a Room database then expose LiveData objects to the ViewModel. The ViewModel in turn exposes LiveData objects to the fragment/activity. The fragment or activity observes the ViewModel's LiveData by attaching an Observer. The Observer defines how the fragment/activity reacts to changes in the data.
If you prefer RXJava you can follow this tutorial instead. It's essentially the same, but instead of exposing data with LiveData you use reactive streams.
Edit: here's a really good article on architecture: https://proandroiddev.com/android-architecture-starring-kotlin-coroutines-jetpack-mvvm-room-paging-retrofit-and-dagger-7749b2bae5f7
Related
These are some general questions with respect to LiveData in Android.
Is it advisable to create UI objects based on LiveData?
If yes, and I have the UI object state depend on another piece of LiveData, don't I automatically create a race condition?
Alternatively stated, how do I ensure that the state is updated based on LiveData value, if the objects are dynamically created based on an observer of different LiveData? As far as I understand I can not simply read the LiveData state information during creation of the objects.
I'm diving into Kotlin Flow for the first time, and I'm wondering if with it ViewModel has a place anymore. ViewModel's advantage was that it was lifecycle aware and would automatically cancel subscriptions on the ViewModel's LiveData when the Activity gets destroyed. A Kotlin SharedFlow works similarly to LiveData in that it can be subscribed to by multiple observers. And in Kotlin a lifecycleScope coroutine should cancel all child coroutines upon the lifecycle ending. So if we had something like this:
lifecycleScope.launch(Dispatchers.IO) {
//Do something
flow.emit(result)
}
lifecycleScope.launch(Dispatchers.Main) {
flow.collect {
//Display the data
}
}
This should cancel when the lifecycle goes out of scope. Am I missing a problem here? Or is there a good reason to use ViewModels anyway? Assume here that there are no 3rd party libraries I need to interact with that expect LiveData or ViewModels.
Keeping the whole discussion aside of LiveData vs SharedFlow or StateFlow. Coming onto ViewModels as you asked. If we are to go by documentation
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
UI controllers such as activities and fragments are primarily intended to display UI data, react to user actions, or handle operating system communication, such as permission requests. Requiring UI controllers to also be responsible for loading data from a database or network adds bloat to the class. Assigning excessive responsibility to UI controllers can result in a single class that tries to handle all of an app's work by itself, instead of delegating work to other classes. Assigning excessive responsibility to the UI controllers in this way also makes testing a lot harder.
It's easier and more efficient to separate out view data ownership from UI controller logic.
I guess this sums it up quite well. It is true that lifeCycleScope can eliminate the need of ViewModel in a way, but ViewModel does more than just being a holder for LiveData.
Even if you want to use SharedFlow or StateFlow over LiveData I would suggest you still make use of ViewModel and inside it use a viewModelScope instead to still perform the usual and required separation of concerns between UI and data.
ViewModel survives configuration changes. Activities and Fragments do not. That’s the primary purpose of ViewModel. ViewModel does not automatically cancel subscriptions to its LiveData. LiveData does that for itself independently. For that reason, the existence of SharedFlow has no impact whatsoever on the usefulness of ViewModel.
If you’re following an MVVM pattern and using ViewModel as the VM, then using SharedFlow instead of LiveData takes it a step closer to being platform agnostic and being easier to unit test.
Question about using LiveData.
With LiveData you get for free that something like:
listener/subscriber support;
lifeCycle awareness/management;
cross thread marshaling, etc.
We could just use the liveData as the mechanism of delivering between any data repository to ui presentation for almost any case.
However in order to using it, it must bring in some objects that it needed, just like if you were to implement those features yourself there must be some supporting classes to be implemented.
Wondering how much/big the overhead it might be? Is it at a lever of could be simply ignored?
The case like do a search it could use LiveData, ui asking result from repository and observes a liveData, the repository posts the result and UI gets notified.
The same could be done without liveData as well (i.e. run coroutines suspended function to fetch from repository directly).
Would like to know whether the LiveData will bring some unnecessary objects, or the benefit over weigh them.
Saw some post but did not find an official guid on when should use/ or not use LiveData, or LiveData is not suitable for such and such cases. Maybe it's just no overhead at all?
Any suggestion/thought?
When working with MVVM (Model View ViewModel) you have two primary options to send data from the ViewModel to the View (updating the View).
Data Binding
LiveData
If you don't want to complicate the XML layout we usually use LiveData, which works based on Observer Design Pattern.
Using Kotlin Coroutines won't bring the full-featured package of LiveData.
With LiveData you have postValue from another thread to main thread,
You can observe changes from inside the view, and ...
PLUS: Kotlin Coroutines are for multithreading which is not relevant to LiveData, a component for holding data.
I have been testing Livedata and AAC in general.
What is the core difference between LiveData and ObservableField?
Which one is the best and when should I use one over another?
The core difference is that ObservableField<T> is not lifecycle-aware and hence there cannot be any automatic subscription management. While LiveData<T> is lifecycle-aware and solves tons of headaches with subscription management when it comes to Activity/Fragment lifecycles.
There is no one way to answer what is the best to use. It is a personal choice, but I would suggest using LiveData<T> just to save yourself some time and avoid potential issues in the future.
Both LiveData and Observable could be used alternatively. LiveData is lifecycle aware and hence will notify only the observables which are "active".
Quoting official documentation on https://developer.android.com/topic/libraries/data-binding/architecture#livedata
Unlike objects that implement Observable—such as observable fields—LiveData objects know about the lifecycle of the observers subscribed to the data changes. This knowledge enables many benefits, which are explained in The advantages of using LiveData. In Android Studio version 3.1 and higher, you can replace observable fields with LiveData objects in your data binding code.
As mentioned both are usable for UI binding interchangeably. LiveData is a quick method but if you want more control on the binding Obserable is a way to go with.
Quoting official documentation on https://developer.android.com/topic/libraries/data-binding/architecture#observable-viewmodel
There are situations where you might prefer to use a ViewModel component that implements the Observable interface over using LiveData objects, even if you lose the lifecycle management capabilities of LiveData. Using a ViewModel component that implements Observable gives you more control over the binding adapters in your app. For example, this pattern gives you more control over the notifications when data changes, it also allows you to specify a custom method to set the value of an attribute in two-way data binding.
We get options to customize the binding in case of an Observable which might be helpful in some case.
Personal preference is to go with LiveData. In case some some customization or more control is needed on the binding go for Obervable
Similarities
Work well with data binding
Bound views automatically unsubscribe when in the background
POJO classes can also subscribe to changes
Differences
LiveData allows for POJO subscribers to be lifecycle aware. Meaning that if you have a property B that you want to update when A changes, you can opt to not receive updates when the attached view is inactive. This saves resources.
Background thread updates of ObservableField<T> are immediate. MutableLiveData.postData is delayed.
Values of LiveData<T> and ObservableField<T> are always nullable, but the primitive implementations ObservableInt, -Float, -Boolean etc are non-nullable.
MutableLiveData<T> doesn't take a constructor value to set on initialization.
When to use what
Do you have external events that may trigger cascading data change in the ViewModel when the app is in the backgrond? You should probably go for LiveData
Do you require value update on background threads to be immediate*? Use Observables
None of the above requirements? You can't go wrong with either but ObservableField is a simpler class.
*) "Immediate" in the sense that a get directly after a set/postValue is guaranteed to return the value you just set. None of the types are of course immediate when it comes to UI update.
Currently i want to create an app with some sort of registration and payment flow.
I use the MaterialStepper library to have one Activity with Fragments each representing one step in the flow.
The Activity has a Android Architecture Component ViewModel and the ViewModel contains several properties for the Fragment. I use LiveData and two-way Databinding for my input fields.
Some data is reused in several Fragments thats why i used only one ViewModel for several fragments.
When the application is in foreground it works like expected, Fragments get re-created and the fields keep their values.
My problem is now when I pause the activity and resume it later. The ViewModel itself can get recreated as well and therefore looses its data.
What is a good approach to avoid the loss of data in that situation?
I read in an article that you should store some values in onSaveInstanceState (e.g. a searchquery to recreate the ViewModel). But isn't that way to much in my situation for ~30 input fields?)
Is a Room database a good approach to insert/update values in the database when the user edits the input fields and observe that LiveData objects instead? (unfortunately i have no experience with Room yet)
I would be glad about any help or examples (: