I have a FirebaseMessagingService which when receiving a new Message should make a network call to retrieve some data to show in a Fragment.
To do so I implemented a MVVM pattern, resulting in a Fragment, a ViewModel and a Repository.
Right now I am directly calling the Repository from within the Service to retrieve the needed data. Unfortunately because it's not the ViewModel doing the call the ViewModel's data (observable) is not being updated, thus the Fragment too.
I know I should not pass a reference to a ViewModel, especially not from a service.
So my question is : how do I update the data in the ViewModel if the Repository is not called from that ViewModel ?
So my entrypoint is the service, but the end result should be that my fragment is being updated with fresh data !
As you said, it is not recommended to call a ViewModel from a Service directly! But here is another BAD solution you can use; you can use Message Bus to communicate between that service and your ViewModel or Fragment; when your Service receives a new message, it can publish an event on the message bus indicating that new data is available. The ViewModel can then subscribe to this event and fetch the data from the Repository when the event is received. Once the data is fetched, the ViewModel can update its observable data, triggering the Fragment to update.
Other than that, you can broadcast a message from the service and register a broadcast receiver in your fragment. When you get the broadcast, you can then ask the viewModel to update and fetch the data!
Related
So, I am using workmanager to retrieve data from an FTP server. I have to display one type or information or another type deppending on the state of the worker.
I was using getWorkInfoByIdLiveData on the viewmodel and I was observing the state of the worker on the activity. But, as the Observer is almost deprecated I am trying to use Flow instead.
The problem that I have is that I don't know why, I can't use the asStateFlow() on the livedata. enter image description here
Does anyone know a way to observe the state of a worker without using LiveData and Observer?
Thank youuu
I am using the Single-Activity and Multiple-Fragments approach, and I have one fragment that has a ViewModel with LiveData. The UI always changes when there is a change in a remote database (Firebase Realtime Database). I followed steps that are described in the offical Firebase Blog (https://firebase.googleblog.com/2017/12/using-android-architecture-components.html). However, the fragment, which the LiveData and ViewModel are bound to, is not active (because I navigated to another fragment) I don't get a notification if something changes in the database.
What I would actually want is to get informed when something changes in the Firebase database no matter which fragment is active, because I would like to play a small notification sound such that the user knows that something has changed. When the fragment that is bound to the LiveData is not active, the UI should not be updated, but the notification sound should be played.
My question is whether this is possible with LiveData (Mutable LiveData) in combindation with Firebase Realtime-Database and if so, how can I do this? I think by default, LiveData only notifies and executes code, if the fragment is active.
Reminder: Any idea how to do that? I'll appreciate every comment.
There are a few ways of doing that depending on the desired behavior. If you want to be notified whenever data changes and your application is active you can do the following:
Ensure that you have a data or repository class that is scoped to the lifecycle of the application. Since you are using single activity architecture, you can also use an activity scoped view model.
Firebase already provides you a way of being notified whenever data changes through onDataChange() listener. You should listen to these changes in you data/repo/viewmodel class and react to changes whenever your data changes.
If you have the scoping done correctly, you'll be notified regardless of which fragment you are on. You can then react to those changes (play sound) as needed.
I have a Service that loads data from via http request every second.
I am wondering how to implement the service in my current MVVM structure.
A solution I could think of is to:
View calls method from ViewModel
ViewModel calls method from Repository
Start the Service in the Repository and pass in some LiveData, as Repositories should be responsible for data loading.
Update this LiveData in the Service via postValue().
Observe this LiveData in UI and notify the ViewModel of the changes
In ViewModel get the changed LiveData and update the other LiveData for the View accordingly
Stop the Service based on the outcome of step 6
However, I am wondering if there is no better solution with a more direct communication from Service to ViewModel or even from Service to Repository to ViewModel
Currently, I am using ViewModel to load a list of Shows in my app. Then, I display it in the main screen. It survives to configuration changes and does not provoke memory leaks since ViewModel has this features.
Now I need to do something a bit different. I need to log in a user making a network call to an endpoint using retrofit 2 and rxjava 2, he will type the email and password, and then will be redirected to the MainActivity. Second, I also need to update the user information, he types his new information and then I send to the server.
May I use ViewModel to log in a user or to update user information? If not, what sould I use instead?
What I need
This retrofit 2 call should survive to configuration changes, as rotating the screen, and it can not cause memory leak.
What I tried
Calling retrofit using enqueue() method in the MainActivity. Obs: This approach is not good because it puts to much things in the ui class, it provokes memory leaks.
Using static inner classes. Obs: It does not survive to configuration changes, as I need to cancel the task in onDestroy().
MVP seems fine to login a user.
You can check google sample project, specifically this class
https://github.com/googlesamples/android-architecture/blob/todo-mvvm-databinding/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskViewModel.java
Usually you would trigger the network operation in the model view, while the code for implementing the network logic is written in a different class (ApiManager for example), and then get the results in your ViewModel
LoginViewModel will have an object of some network manager class
When you click login, the viewmodel will call networkManager.performLogin()
Results are then passed to the viewmodel (RxJava is handy in here).
In your ViewModel do whatever processing you need when you receive the results
I am building an app where I store the url and Json in my local SQLite db and then schedule a JobService.
In the JobService, I take out all the requests one by one from the db and execute them. Once they are executed, I get the response inside the JobService only. Now my real problem is how do I send the response back to the user from the service.
I thought of implementing a callback/listener in activity and passing the value in listener object inside the service. But I am taking out the requests from the SQLite db. So I don't know how to save the callback instance or the context inside my database so that I get that with the rest of the data inside the service itself.
Any ideas?
One approach is to use an event bus implementation: LocalBroadcastManager, greenrobot's EventBus, some Rx-based bus, or even a simple MutableLiveData singleton. Have the service post a message on the bus. Have your UI layer register and unregister from the bus as they come and go. Have the UI layer process messages received on the bus, and have the service raise a Notification if the UI layer does not pick up the message.
Here are sample implementations using:
LocalBroadcastManager: https://github.com/commonsguy/cw-omnibus/tree/v8.6/EventBus/LocalBroadcastManager
greenrobot's EventBus: https://github.com/commonsguy/cw-omnibus/tree/v8.6/EventBus/GreenRobot3
MutableLiveData: https://github.com/commonsguy/cw-androidarch/tree/v0.1/General/LiveBus