I have a component in my app that performs specific work when the database gets updated. In order to observe Room table, I need to use LiveData which requires me to pass LifecycleOwner. My component has nothing to do with any of the views so I don't have a Lifecycle. How can I observe on Room table without a reference to LifecycleOwner? I am using Kotlin and Coroutines.
You may use LiveData.observeForever(Observer). Do not forget to call LiveData.removeObserver(Observer) once you do not want to get updates anymore, as using this method you register an observer that will receive updates forever (as the method's name suggests). (Docs source)
Related
We use ViewModels for storing and manipulating data that is to be used by Views in Activity/Fragment - as data in ViewModel survives configuration change which helps us to retain UI state. It is one of the reasons we do network call operations in ViewModel, but is there any other reason we do network call operations in ViewModel?
I read somewhere that if we do network calls in ViewModels, the call does not happen again on configuration change? But I'm pretty sure API call is happening again in my Fragment on changing device orientation.
To overcome this problem you can call your function in init method of viewmodel makeApiCall() to prevent second call due to onViewCreated method. And you can store api result into livedata.
Alternatively, You can also use LiveData scope like this:
val makeApiCall: () -> LiveData<List<Data>> = {
liveData {
emit(repository.fetchData()) // API call
}
}
Call makeApiCall lambda function from your onViewCreated, now API call will emit only one time and your live data will get observed in onViewCreated.
This is the one of the main advantage of viewmodel to prevent API call on orientation change.
Another advantage is, Suppose if you close the screen and now API call is no longer needed so, if you are using RxJava you need to cancel/dispose API call to release resource so you can perform it in onCleared method of viewModel irrespective of orientation change.
Or if you are using coroutine you can use LiveData scope and viewModel
scope no need to care about canceling coroutine. it's managed by self.
We keep api hit in viewModel because of following reasons as per my practices
1)It reduces the coupling between Android components and non Android components
2)You can reuse the same ViewModel for some other screen as well
3) After fetching data you store that data in you liveData holder which can be used data to your UI on it's configuration change without making api hit
I am trying to overwrite a firebase message and I need to use a live data object in a class that is not in an activity but i dont know how to get the LifecycleOwner.
currentUserIDLiveData.observe(this , androidx.lifecycle.Observer{
println("THE CURRENT USER ID IS " + it)
})
If you want to observe it forever and it doesn't matter for you that it could cause memory leak or not, you can use observeForever method of liveData. But if it's necessary to pass the lifecycleOwner and you are not in a common owners like activity and fragment, you should implement your custom lifecycleOwner based on it's base interface and pass it to liveData as well. It's not too hard to implement it, just you have to know when your component is alive and when it's not.
I want to make sure I understand correctly when is the onChanged method of a LiveData's Observer called.
Let's say we have an object A which has some primitives types
(some ints, some strings, etc.) and an object B as fields.
I know that onChanged is called when I call setValue. I'm pretty sure that it is also called when A's primitive fields change, or when I reassign the object field to a new instance, and that it is NOT called when I change any of B's fields.
Please correct me if I'm wrong.
Do these rules also apply to a LiveData object fetched from Room?
Are there any other cases where onChanged is called?
The fact is that the onChanged method of the LiveData's Observer is only called when the containing value of the LiveData is being set using setValue() or postValue() method. There is no mechanism to observe fields inside an object that is held by a LiveData. As a result, by changing the value of fields inside object-A, the observer shouldn't be notified.
On the other hand, as you know, the methods that are provided by Room to query on a db are able to return LiveData<SomeType> instead of SomeType. Under the hood, Room creates and registers a ContentObserver on your query's table(s) to get aware of changes in it. So, every time a change occurs on the data, Room gets notified using the mentioned ContentObserver, then fetches the query result again and post it on the LiveData.
I have some more complex logic for data provided by my ViewModel to the UI, so simply exposing the data via LiveData won't do the job for me. Now I've seen in the Android docs that I can implement Observable on my ViewModel to get the fine-grained control I need.
However in the documentation it also says:
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.
How intelligent is the built-in Android data binding? Will it automatically unregister it's listeners when necessary (e.g. on configuration changes where the View is destroyey) so that I don't have to care about the lost lifecycle capabilities? Or do I have to watch the Lifecycle of the View and unregister it's listeners? (=do manually what LiveData normally does for me).
How intelligent is the built-in Android data binding? Will it automatically unregister it's listeners when necessary (e.g. on configuration changes where the View is destroyey) so that I don't have to care about the lost lifecycle capabilities? Or do I have to watch the Lifecycle of the View and unregister it's listeners? (=do manually what LiveData normally does for me).
So I did some tests. I implemented androidx.databinding.Observable on my ViewModel and did a configuration change with the following log calls:
override fun removeOnPropertyChangedCallback(
callback: androidx.databinding.Observable.OnPropertyChangedCallback?) {
Log.d("APP:EVENTS", "removeOnPropertyChangedCallback " + callback.toString())
}
override fun addOnPropertyChangedCallback(
callback: androidx.databinding.Observable.OnPropertyChangedCallback?) {
Log.d("APP:EVENTS", "addOnPropertyChangedCallback " + callback.toString())
}
I saw that addOnPropertyChangedCallback was invoked for each time my viewmodel was referenced in a layout binding expression. And not once did I see removeOnPropertyChangedCallback invoked. My initial conclusion is that AndroidX databinding is dumb and does not automagically remove the listener.
FYI: the callback type was ViewDataBinding.WeakPropertyListener
However, I took a peek at ViewDataBinding.java source code and found that it is using Weak References to add the listener.
So what this implies, is that upon a configuration change, Android OS should be able to garbage collect your Activity/Fragment because the viewmodel does not have a strong reference.
My advice: Don't add the boilerplate to unregister the listeners. Android will not leak references to your activities and fragments on configuration changes.
Now, if you choose not to use LiveData, consider making your viewmodel implement LifecycleObserver so that you can re-emit the most recent value when your Activity/Fragment goes into the active state. This is the key behavior you lose by not using LiveData. Otherwise, you can emit notifications by using the PropertyChangeRegistry.notifyCallbacks() as mentioned in the documentation you shared at some other time. Unfortunately, I think this can only be used to notify for all properties.
Another thing... while I've not verified the behavior the source code seems to indicate that weak references are used for ObservableField, ObservableList, ObservableMap, etc.
LiveData is different for a couple of reasons:
The documentation for LiveData.observe says that a strong reference is held to both the observer AND the lifecycle owner until the lifecycle owner is destroyed.
LiveData emits differently than ObservableField. LiveData will emit whenever setValue or postValue are called without regard to if the value actually changes. This is not true for ObservableField. For this reason, LiveData can be used to send a somewhat "pseudo-event" by setting the same value more than once. An example of where this can be useful can be found on the Conditional Navigation page where multiple login failures would trigger multiple snackbars.
Nope. ViewModel will not unregister Observable subscription automatically. You can do it manually though. It is pretty easy.
Firstly you create CompositeDisposable
protected var disposables = CompositeDisposable()
Secondly, create your Observable(it may be some request or UI event listener) subscribe to it and assign its result to CompositeDisposable
disposables.add(
someObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ data ->
// update UI or some ObservableFields for view/databinding
}, { exception ->
// handle errors here
})
)
The last thing you should do is to override ViewModel's method onCleared() like this:
override fun onCleared() {
super.onCleared()
disposables.clear()
}
This way all subscription added to your CompositeDisposable will be cleared automatically
Edit
I showed only the example. You may add triggers in onConfigurationChanged or onCreate or onResume to clear subscriptions as well - but it is dependent on specific usecases of an app. I gave just a general one.
Hope it helps.
DataBinding would not do the unregistering for you. Its simply help bind your layout file and the ViewModel. It is the viewModel that will protect you from device's configuration change. You still need to apply onSavedViewState() in your base activity or fragment as viewModel does not cover that. As per unregistering, LiveData does that.
As #Pavio already taught you how to create Observable, that is RxJava working. I would suggest using kotlin's coroutines and viewModel with LiveData to get the best out of your situation. Rx has a learning curve to it, although it does offer hundred of operators for all sorts of operations. If you really want to learn the kotlin way, look into kotlin flows and channels.
If i was in your place, I would solve my problem with ViewModels, LiveData and Coroutines.
I'm building an android application with MVVM design and I have multiple layers(view, ViewModel, repository and dataSource both local and remote).
I want that my repository object will observe the dataSources, do all of his logic for how and when storing cache, map the data to the correct form for the above layer and only then notify the view model about the new data.
Similar to that I want the ViewModel to observe the repository for new data arrival, then doing all the business logic and only after that notify the view.
My problem is that LiveData require lifecycle object that the ViewModel and
the repository doesn't have.
I read about using simple observable rather than LiveData but I also read that it is bad practice because the observables are alive forever and this could lead to wierd crashes. In addition, I have PageKeyedDataSource which only returns LiveData.
I also read about using Transformations.map but what if I don't want only to map the data but rather to do something more complex.
Is There a way to make one layer safely observe another layer without creating a chain of LiveData observables from the view layer to the DataSource?
note: my ViewModel is used in multiple fragments if that somehow relevant.
My problem is that LiveData require lifecycle object
Actually, lifecycle is optional. There is an observeForever(Observer) method in LiveData that does not require lifecycle. But that means you should also manually call removeObserver(Observer) when your repository finished work, otherwise it will be a leak.
This really is not much different to using Rx's observables. In both cases you should override onCleared() in your viewmodel and manually unsubscribe (or remove observer) from the repository.
observables are alive forever and this could lead to wierd crashes
Nope, they are alive until you dispose them, but you must do it manually as Rx does not provide lifecycle-aware subscription.
Is There a way to make one layer safely observe another layer without creating a chain of LiveData observables from the view layer to the DataSource?
As your wrote, you are trying to do a View-that-observes-ViewModel-that-observes-Repo-that-observes-DataSource. It is already a chain, you should deal with it.
It is possible to to safely observe LiveData from ViewModel, cause View has a lifecycle and LiveData has lifecycle-aware observe.
But Repo and DataSource do not have lifecycles thus you should manually manage subscriptions. It is possible both with LiveData and Rx observables - you can choose whichever you prefer.
1.First of all, if you need context in viewmodel use AndroidViewModel .
2.Don't do any business logic in Viewmodel class as it's just mediator rather do calculations in repository class
3.use rxjava/rxkotlin in repository and return observable object to Viewmodel from repository method, once Viewmodel gets notified update view.
You could use DataBinding to reflect the ViewModel data in you UI. https://developer.android.com/topic/libraries/data-binding
An added benefit is that you write less boilerplate code.