MVVM - Accessing ViewModel/SQLite in a BroadcastReceiver started from a notification when app is closed

。_饼干妹妹 提交于 2021-02-07 14:15:36

问题


I have a reminder notification that is sent every few days.

The sending of that notification is triggered with a repeating AlarmManager. The notification itself is built in the onReceive of my BroadcastReceiver (as described here). So when onReceive is triggered, the app is not even open/running.

Now at that point I want to access my (local) SQLite database and get the correct content to build the notification with, but how would I get a ViewModelProvider (xxx in the code) in this place to even access my ViewModel?

public void onReceive(Context context, Intent intent) {    

    NotificationViewModel viewModel = 
    ViewModelProviders.of(XXX).get(NotificationViewModel.class);

    //do stuff
}

Or to ask the better question, is that even good practice?
The other possibility would be stuffing all the content in the PendingIntent that will trigger the onReceive, so I could retrieve it one by one once received. But that would be even harder, since it's a repeating alarm and needs different content every time but is triggered only once.


I've looked at a few search results but they did not solve my issue:

  • MVVM Architecture for Custom Views on Android
    -> Seems like a lot of code for such a minor issue, plus being Kotlin, which is hard to understand for me
  • Dealing with BroadcastReceivers using the Model View Presenter design pattern
    -> Here it seems like it is necessary to set up a few things in the activities first, before even being able to use it, but I need to start this code without having my application running
  • Accessing BroadCastReceiver in Viewmodel
    -> This seems like the closest to what I need, but it also needs previous setting up before. I wanted to try this but I would need to manually create my MainActivity to access its variables like that. Wouldn't that open a new activity on the user's device without warning?
    Is it even possible to access my database without my app being in the foreground?

Edit:

Reading LiveData beyond the ViewModel [...], it is said

If part of your app doesn’t affect the UI, you probably don’t need LiveData.

So that means I should simply access my repository with the context and get the raw data out of it, without the LiveData wrapper?

So

public void onReceive(Context context, Intent intent) {

    NotificationRepository rp = new NotificationRepository(context);
    MessageNotification notification = rp.getNextNotification();
}

instead of

public void onReceive(Context context, Intent intent) {

    NotificationViewModel viewModel = 
    ViewModelProviders.of(XXX).get(NotificationViewModel.class);
    MessageNotification notification = 
    viewModel.getNextNotification().observe(XXX, new 
         Observer<MessageNotification>() {
            @Override
            public void onChanged(MessageNotification messageNotification) {
                //do stuff
            }
         });
}

But does this go against the MVVM convention?
Should I use some other architecture? Right now it seems to make sense to me, since it's something I only retrieve once and don't have to observe for changes.


回答1:


What is the real purpose of ViewModel in this situation?
Will it transform your data to some view-convenient format?
Will it handle data updates? (I mean, will there ever be data updates? Seems you have one notification in a while)
Or will it just clutter clean, synchronous code and make it async for no real purpose?

If you answer 'yes' only to the last question, you probably do not need ViewModel here:) Do you need other architecture? No, you need no architecture. You need to display a notification, so just do it!


If you are a real MVVM fan, you still can pass.
Firstly, drop ViewModelProviders.of cause it is impossible to use here. It requires activity or fragment and you have neither of them. Purpose of ViewModelProvider is to deliver you same instance of viewmodel when activity/fragment is recreated - it is clearly NOT your case.
Secondly, construct viewmodel yourself: new NotificationViewModel().
Thirdly, return the normal object from your viewmodel instead of livedata, cause your data is not live.

public class NotificationViewModel {
    MessageNotification getNextNotification() {
        // ...
    }
}

Note that you even do not need to extend ViewModel class, cause you do not use ViewModelProviders.




回答2:


If the issue is to read SQLite DB then no ViewModel is required. The issue maybe that suspend functions can not be called directly (viewmodelscope.launch{}), but there is an easy fix: runBlocking.

I assume the Broadcastreceiver is in the background already, so there is no need to launch a background coroutine.

runBlocking {
   val reminders = favoriteDao.queryAllReminders()
   reminders.forEach { reminder ->
       Log.i("Reminder", reminder.info)
   }
}


来源:https://stackoverflow.com/questions/56100168/mvvm-accessing-viewmodel-sqlite-in-a-broadcastreceiver-started-from-a-notifica

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!