ViewModel при реализации Room in Foreground Service

В настоящее время у меня есть приложение с ForegroundService для всех взаимодействий сервера/API и база данных Room для локального сохранения. Я пытался реализовать AndroidViewModel, чтобы помочь с сохранением данных и быстрым обновлением пользовательского интерфейса.

Однако, согласно документации, ViewModels не могут быть реализованы в Службах, поэтому далеко я использовал Службу для локального обновления информации и уведомления компонентов с помощью LocalBroadcasts (это то, что я хочу исключить с помощью ViewModels и Observers).

Мне нужно, чтобы служба работала, так как приложение должно продолжать работать в фоновом режиме (это критически важное приложение, а закрытие приложения означает, что пользователь не будет доступен для предоставления критически важных услуг) и периодически обновлять определенную информацию. (ближайшие запросы и т.д.).

Итак, чтобы задать основной вопрос -

  1. Как отделить службу от ViewModel, и если у службы есть последние синхронизированные данные с серверов, как обновить списки (изменяемых) LiveData в моей ViewModel?
  2. Эта статья и этот ответ на вопрос здесь, на SO говорит лучше отделить ViewModel от репозитория, пока это другой один дает пример включения базы данных Room внутри ViewModel. Какой вариант лучше?

Часть моего кода ViewModel выглядит следующим образом:

 public class HouseCallViewModel extends AndroidViewModel {

        private String TAG = HouseCallViewModel.class.getSimpleName();

        private MutableLiveData<List<HouseCall>> housecallList;
        private MutableLiveData<List<HouseCall>> openHousecalls, confirmedHousecalls, closedHousecalls, missedHousecalls, userCancelledHousecalls, respCancelledHousecalls;
        private MutableLiveData<List<Incident>> incidentList, openIncidents;
        private MutableLiveData<List<Incident>> closedIncidents, usercancelIncidents, respcancelIncidents;
        RevivDatabase database;
        Context context;


        public HouseCallViewModel(Application application) {
            super(application);

            //      DANGER WILL ROBINSON                                            
            context = application.getApplicationContext();
            database = Room.databaseBuilder(this.getApplication(),
                    RevivDatabase.class, application.getResources().getString(R.string.database)).build();
        }
        public LiveData<List<HouseCall>> getHousecallList() {
                if (housecallList == null) {
                    housecallList = new MutableLiveData<>();
                    loadHousecalls(); // need to call API and sync
                }
                return housecallList;
            }
       public LiveData<List<HouseCall>> getIncidentList() {
                    if (incidentList == null) {
                        incidentList = new MutableLiveData<>();
                        loadIncidents(); // need to call API and sync
                    }
                    return housecallList;
                }

    // other constructors, getters and setters here, and functions to update the data
    }

person kilokahn    schedule 23.07.2018    source источник


Ответы (1)


1)

Поскольку вы не предоставили сведения о коде своей Службы и связанных с ней компонентов, этот ответ является абстрактным.

Чтобы отделить ViewModel от службы, создайте действие, которое будет обращаться к ViewModel; у вас будет Activity, ViewModel и Service.

Это означает, что вы создадите связанную службу (https://developer.android.com/guide/components/services#CreatingBoundService и, в частности, https://developer.android.com/guide/components/bound-services). Связанная служба предоставляет интерфейс, который действие может использовать для взаимодействия со службой.

Хорошим примером связанной службы является служба обновления местоположения Google: https://github.com/googlesamples/android-play-location/tree/master/LocationUpdatesForegroundService/app/src/main/java/com/google/android/gms/location/sample/locationupdatesforegroundservice

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

Для передачи данных из Сервиса в ViewModel я предлагаю использовать EventBus Greenrobot (http://greenrobot.org/eventbus/documentation/how-to-get-started/).

Всякий раз, когда вы хотите, чтобы Служба передавала данные в ViewModel, однострочный вызов EventBus в вашей Службе будет передавать данные подписчикам в действии, которые прослушивают этот тип данных.

Затем Activity после получения данных обновит ViewModel данными. После этого все наблюдатели, зарегистрированные в ViewModel, получат самые последние данные.

2)

Принцип разделения ответственности выступает за отделение ViewModel от репозитория. Модель представления должна заботиться только о сохранении состояния данных, которые будут отображаться пользователю, и сохранении такого состояния при изменении конфигурации.

person loroz    schedule 23.07.2018
comment
Большое спасибо за ответ. Извините, я не мог быть более подробным - я не знал, что включить, а что опустить, так как боялся, что мой вопрос будет раздут до неузнаваемости. Если бы вы могли указать информацию, которую хотели бы, я могу обновить вопрос. - person kilokahn; 24.07.2018
comment
Кроме того, будет ли ViewModel эффективна, если я обновлю/изменю данные в базе данных Room из Сервиса и настрою Observer на ObserveForever в списке LiveData‹Object›, возвращаемом DAO? - person kilokahn; 24.07.2018
comment
Без проблем! Я бы хотел получить ясность в комментариях, прежде чем публиковать ответ, но у меня не было для этого представителя. Что касается вашего третьего вопроса, статья, на которую вы ссылаетесь (medium.com /google-developers/) есть раздел LiveData в репозиториях. Исходя из этого, похоже, что вы можете наблюдать за изменениями данных в базе данных. Если вы хотите сохранить ту же структуру приложения, которая у вас уже есть (т. е. Служба и база данных), я бы предложил пойти по этому пути, хотя на данный момент мне это не известно. - person loroz; 24.07.2018
comment
Я рассмотрел реализацию вашего решения - отправку данных обратно в действие, а затем обновление базы данных там, - но решил в пользу третьего маршрута, создав класс доступа к базе данных Singleton, а затем обновив репо из самой службы. Поскольку в моей ViewModel есть DAO с функциями, возвращающими LiveData‹List‹POJO››, моя активность использует ViewModel для доступа к оперативным данным. Тем не менее, большое спасибо за содержательный ответ. Если бы вы могли отредактировать свой ответ и добавить это как решение, я был бы рад принять его :) - person kilokahn; 27.07.2018