MVVM — доступ к ViewModel/SQLite в BroadcastReceiver начался с уведомления при закрытии приложения

У меня есть уведомление-напоминание, которое отправляется каждые несколько дней.

Отправка этого уведомления инициируется повторяющимся AlarmManager. Само уведомление встроено в onReceive моего BroadcastReceiver (как описано здесь). Поэтому, когда запускается onReceive, приложение даже не открывается/не работает.

Теперь в этот момент я хочу получить доступ к своей (локальной) базе данных SQLite и получить правильный контент для создания уведомления, но как мне получить ViewModelProvider (xxx в коде) в этом месте, чтобы даже получить доступ к моему ViewModel?

public void onReceive(Context context, Intent intent) {    

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

    //do stuff
}

Или, лучше задать вопрос, является ли это хорошей практикой?
Другая возможность заключается в том, чтобы запихнуть весь контент в PendingIntent, который вызовет onReceive, чтобы я мог получить его один за другим после получения. Но это было бы еще сложнее, так как это повторяющийся будильник, и каждый раз требуется разное содержимое, но он срабатывает только один раз.


Я просмотрел несколько результатов поиска, но они не решили мою проблему:

  • Архитектура MVVM для пользовательских представлений на Android
    -> Похоже, много кода для такой незначительной проблемы, плюс это Kotlin, что мне трудно понять
  • Действие с BroadcastReceivers с использованием шаблона проектирования Model View Presenter
    -> Здесь кажется, что сначала необходимо настроить несколько вещей в действиях, прежде чем даже можно будет их использовать, но мне нужно начать это код без запуска моего приложения
  • Доступ к BroadCastReceiver в Viewmodel
    -> Это кажется наиболее близким к тому, что я need, но также требует предварительной настройки. Я хотел попробовать это, но мне нужно было бы вручную создать мою MainActivity для доступа к ее переменным. Разве это не приведет к новой активности на устройстве пользователя без предупреждения?
    Возможно ли вообще получить доступ к моей базе данных без того, чтобы мое приложение было на переднем плане?

Редактировать:

Чтение LiveData за пределами ViewModel [ ...], сказано

Если часть вашего приложения не влияет на пользовательский интерфейс, вам, вероятно, не нужны LiveData.

Это означает, что я должен просто получить доступ к моему репозиторию с помощью контекста и получить из него необработанные данные, без оболочки LiveData?

So

public void onReceive(Context context, Intent intent) {

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

вместо

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
            }
         });
}

Но противоречит ли это соглашению MVVM?
Должен ли я использовать какую-то другую архитектуру? Сейчас мне кажется, что это имеет смысл, поскольку это то, что я получаю только один раз, и мне не нужно наблюдать за изменениями.


person Big_Chair    schedule 12.05.2019    source источник


Ответы (2)


Какова реальная цель ViewModel в этой ситуации?
Будет ли она преобразовывать ваши данные в какой-либо удобный для представления формат?
Будет ли она обрабатывать обновления данных? (Я имею в виду, будут ли когда-нибудь обновления данных? Кажется, вы получаете одно уведомление через некоторое время)
Или оно просто загромождает чистый синхронный код и делает его асинхронным без какой-либо реальной цели?

Если вы ответите «да» только на последний вопрос, то ViewModel вам здесь, скорее всего, не нужен :) Нужна другая архитектура? Нет, вам не нужна архитектура. Вам нужно отобразить уведомление, так что просто сделайте это!


Если вы настоящий фанат MVVM, вы все равно можете пройти мимо.
Во-первых, отбросьте ViewModelProviders.of, потому что его здесь нельзя использовать. Это требует активности или фрагмента, и у вас нет ни того, ни другого. Целью ViewModelProvider является предоставление вам одного и того же экземпляра модели представления при воссоздании действия/фрагмента - это явно НЕ ваш случай.
Во-вторых, создайте модель представления самостоятельно: new NotificationViewModel().
В-третьих, верните обычный объект из вашей модели представления вместо livedata, потому что ваши данные не актуальны.

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

Обратите внимание, что вам даже не нужно расширять класс ViewModel, потому что вы не используете ViewModelProviders.

person dhabensky    schedule 18.05.2019
comment
Да, это в основном то, что я сделал, просто использовал AsynTask, чтобы получить данные из репозитория самостоятельно, без вещей ViewModel и LiveData, поскольку в этом случае это действительно не добавляет никакой ценности. - person Big_Chair; 19.05.2019

Если проблема заключается в чтении базы данных SQLite, ViewModel не требуется. Проблема может заключаться в том, что функции приостановки нельзя вызывать напрямую (viewmodelscope.launch{}), но есть простое решение: runBlocking.

Я предполагаю, что Broadcastreceiver уже находится в фоновом режиме, поэтому нет необходимости запускать фоновую сопрограмму.

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