android - 在前台服务中实现 Room 时的 ViewModel
问题描述
我目前有一个应用程序,其中包含用于所有服务器/API 交互的 ForegroundService,以及用于本地持久性的 Room 数据库。我一直在尝试实现一个 AndroidViewModel 来帮助实现数据持久性和快速 UI 刷新。
但是,根据文档,ViewModels 不能在 Services 中实现,到目前为止,我已经使用 Service 在本地更新信息并使用 LocalBroadcasts 通知组件(这是我想使用 ViewModels 和 Observers 消除的)。
我需要让服务运行,因为应用程序需要在后台继续运行(它是一个关键任务应用程序,应用程序关闭意味着用户将无法提供关键服务),并定期更新某些信息(附近的请求等)。
所以要问核心问题——
- 如何将服务与 ViewModel 分开,如果服务具有来自服务器的最新同步数据,如何更新 ViewModel 中的(可变)LiveData 列表?
- This article和this answer to a question here on SO 说最好将ViewModel与Repository分开,而另一篇则给出了将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
}
解决方案
1)
由于您没有提供有关您的服务及其相关组件的代码详细信息,因此此答案是抽象的。
要将 ViewModel 从 Service 中分离出来,请创建一个将访问 ViewModel 的 Activity;您将拥有一个 Activity、一个 ViewModel 和一个 Service。
这意味着您将创建一个绑定服务(https://developer.android.com/guide/components/services#CreatingBoundService,更具体地说,是https://developer.android.com/guide/components/bound-services) . 绑定的 Service 提供了一个 Activity 可以用来与 Service 交互的接口。
绑定服务的一个很好的例子是谷歌的位置更新服务:https ://github.com/googlesamples/android-play-location/tree/master/LocationUpdatesForegroundService/app/src/main/java/com/google/android/gms /location/sample/locationupdatesforegroundservice
在您的实例中,Service 将负责生成数据并将该数据传输到 Activity,Activity 再将该数据提供给 ViewModel。
要将数据从服务传输到 ViewModel,我建议使用 Greenrobot 的 EventBus ( http://greenrobot.org/eventbus/documentation/how-to-get-started/ )。
每当您希望 Service 将数据传输到 ViewModel 时,在 Service 中对 EventBus 的单行调用会将数据传输到 Activity 中正在侦听该类型数据的订阅者。
Activity 收到数据后,将使用数据更新 ViewModel。任何注册到 ViewModel 的观察者都会收到最新的数据。
2)
关注点分离原则有利于将 ViewModel 从存储库中分离出来。ViewModel 应该只关心保持将向用户显示的数据的状态,并在配置更改时保持这种状态。
推荐阅读
- angular - 如何为 Angular 中的二进制下载指定 OpenAPI
- postgresql - 如何将事务与 PQexecPrepared libpq 一起使用
- ruby-on-rails - 带有匹配选择的rails提交复选框
- python - 用于解密文件、添加所需元数据并将它们发送到 S3 存储桶的 Lambda 函数
- php - 每次在 gCloud App Engine 上调用任何 PHP 时,YAML 都会呈现 index.html
- python - Python循环未运行
- javascript - 如何通过 Angular Material Select 使用用户选择的值进行过滤?
- javascript - 遍历 ember.js 车把模板中的键值对
- java - 检查 SQLITE 数据库是否为空会冻结应用程序
- ios - 快速应用程序崩溃,错误引导 BKSProcessErrorDomain