如何从服务中的 Room 数据库读取数据并监听更改?
How to read data and listen to changes from Room database in a Service?
我正在将用户信息存储在本地房间数据库中。在活动和片段中,我使用 AndroidViewModel 和 LiveData 来监听对数据库所做的更改并更新 UI.
现在我想分析所有过去的用户数据,为未来的决策提供建议。我的建议会随着用户对数据库所做的每次更改而改变,因此我需要经常更新我的建议,同时一遍又一遍地进行相同的计算。
我正在考虑在应用程序启动时启动一项服务,该服务通过 ViewModel 和 LiveData 侦听数据库更改并更新我的建议(也存储在同一数据库中)。但不知何故服务不能
- 通过
viewModel = ViewModelProviders.of(this).get(DataViewModel.class);
获取 ViewModel
- 观察 LiveData 对象,因为它不是 LifecycleOwner。
基本上我只需要从数据库中读取所有条目,分析数据并在每次数据库内容更改时更新 5-10 个值。
如果不在服务中,我应该如何以及在哪里进行计算?也许我被困在一个错误的想法中,服务不是正确的方法,所以非常感谢任何关于如何做到这一点的想法!
observe a LiveData object as it is not a LifecycleOwner
在 LiveData
上使用 observeForever()
,在适当的时候通过 removeObserver()
手动注销(onDestroy()
服务,如果不是更快的话)。
请记住,此处适用标准服务限制(例如,服务 运行 在 Android 8.0+ 上持续约 1 分钟,除非它们是前台服务),因此您可能需要无论如何都要考虑其他方法。
我最终使用了一项服务并按如下方式解决了我的问题:
在我的 Application object
的 onCreate
方法中,我将 MyService
绑定到它:
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
service = ((MyService.MyLocalBinder) iBinder ).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
Intent intent = new Intent(this, MyService.class);
getApplicationContext().bindService(intent, serviceConnection, BIND_AUTO_CREATE);
只要应用程序未被销毁,将服务绑定到应用程序上下文应该使服务保持活动状态。在 MyService
中,我通过 AndroidViewModelFactory
像这样
获得了一个 ViewModel 实例
MyViewModel myViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(MyViewModel.class);
并且我能够通过 observeForever
像这样
观察从 ViewModel 获取的 LiveData
Observer<List<Entry>> obsEntries = new Observer<List<Entry>>() {
@Override
public void onChanged(@Nullable List<Entry> entries) {
//perform calculations with entries in here
}
};
viewModel.getEntries().observeForever(obsEntries);
重要提示: 从服务的 onDestroy
中的 LiveData 引用中删除观察者(这就是我保留对观察者对象的本地引用的原因):
@Override
public void onDestroy() {
super.onDestroy();
viewModel.getEntries().removeObserver(obsEntries);
}
谢谢大家!
实体中无需更改。
在 DAO 中,例如,
@Dao
public interface TimeDao {
// ...
// ...
// for a started Service using startService() in background
@Query("select * from times where name = :bName")
List<TimeEntity> getServiceTimes(String bName);
}
这不是 LiveData
在数据库中,例如,
@Database(entities = {DataEntity.class, TimeEntity.class}, version = 1)
public abstract class BrRoomDatabase extends RoomDatabase {
public abstract TimeDao iTimeDao();
public static BrRoomDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
// ...
}
return INSTANCE;
}
}
一个接口class
public interface SyncServiceSupport {
List<TimeEntity> getTimesEntities(String brName);
}
它的实现 class。
public class SyncServiceSupportImpl implements SyncServiceSupport {
private TimeDao timeDao;
public SyncServiceSupportImpl(Context context) {
timeDao = BrRoomDatabase.getDatabase(context).iTimeDao();
// getDatabase() from where we get DB instance.
// .. and ..
// public abstract TimeDao iTimeDao(); <= defined abstract type in RoomDatabase abstract class
}
@Override
public List<TimeEntity> getTimesEntities(String name) {
return timeDao.getServiceTimes(name);
}
}
最后...在服务中..
public class SyncService extends Service {
//..
// now, iEntities will have a List of TimeEntity objects from DB ..
// .. retrieved using @Query
private static List<TimeEntity> iEntities = new ArrayList<>();
private static SyncServiceSupportImpl iSyncService;
private static void getFromDB(String brName) {
new AsyncTask<String, Void, Void>() {
@Override
protected Void doInBackground(String... params) {
iEntities = iSyncService.getTimesEntities(params[0]);
return null;
}
@Override
protected void onPostExecute(Void agentsCount) {
}
}.execute(brName);
}
@Override
public void onCreate() {
super.onCreate();
//init service
iSyncService = new SyncServiceSupportImpl(SyncService.this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// this can be elsewhere also !..
getFromDB(myName);
}
}
我正在将用户信息存储在本地房间数据库中。在活动和片段中,我使用 AndroidViewModel 和 LiveData 来监听对数据库所做的更改并更新 UI.
现在我想分析所有过去的用户数据,为未来的决策提供建议。我的建议会随着用户对数据库所做的每次更改而改变,因此我需要经常更新我的建议,同时一遍又一遍地进行相同的计算。
我正在考虑在应用程序启动时启动一项服务,该服务通过 ViewModel 和 LiveData 侦听数据库更改并更新我的建议(也存储在同一数据库中)。但不知何故服务不能
- 通过
viewModel = ViewModelProviders.of(this).get(DataViewModel.class);
获取 ViewModel
- 观察 LiveData 对象,因为它不是 LifecycleOwner。
基本上我只需要从数据库中读取所有条目,分析数据并在每次数据库内容更改时更新 5-10 个值。
如果不在服务中,我应该如何以及在哪里进行计算?也许我被困在一个错误的想法中,服务不是正确的方法,所以非常感谢任何关于如何做到这一点的想法!
observe a LiveData object as it is not a LifecycleOwner
在 LiveData
上使用 observeForever()
,在适当的时候通过 removeObserver()
手动注销(onDestroy()
服务,如果不是更快的话)。
请记住,此处适用标准服务限制(例如,服务 运行 在 Android 8.0+ 上持续约 1 分钟,除非它们是前台服务),因此您可能需要无论如何都要考虑其他方法。
我最终使用了一项服务并按如下方式解决了我的问题:
在我的 Application object
的 onCreate
方法中,我将 MyService
绑定到它:
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
service = ((MyService.MyLocalBinder) iBinder ).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
Intent intent = new Intent(this, MyService.class);
getApplicationContext().bindService(intent, serviceConnection, BIND_AUTO_CREATE);
只要应用程序未被销毁,将服务绑定到应用程序上下文应该使服务保持活动状态。在 MyService
中,我通过 AndroidViewModelFactory
像这样
MyViewModel myViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(MyViewModel.class);
并且我能够通过 observeForever
像这样
Observer<List<Entry>> obsEntries = new Observer<List<Entry>>() {
@Override
public void onChanged(@Nullable List<Entry> entries) {
//perform calculations with entries in here
}
};
viewModel.getEntries().observeForever(obsEntries);
重要提示: 从服务的 onDestroy
中的 LiveData 引用中删除观察者(这就是我保留对观察者对象的本地引用的原因):
@Override
public void onDestroy() {
super.onDestroy();
viewModel.getEntries().removeObserver(obsEntries);
}
谢谢大家!
实体中无需更改。
在 DAO 中,例如,
@Dao
public interface TimeDao {
// ...
// ...
// for a started Service using startService() in background
@Query("select * from times where name = :bName")
List<TimeEntity> getServiceTimes(String bName);
}
这不是 LiveData
在数据库中,例如,
@Database(entities = {DataEntity.class, TimeEntity.class}, version = 1)
public abstract class BrRoomDatabase extends RoomDatabase {
public abstract TimeDao iTimeDao();
public static BrRoomDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
// ...
}
return INSTANCE;
}
}
一个接口class
public interface SyncServiceSupport {
List<TimeEntity> getTimesEntities(String brName);
}
它的实现 class。
public class SyncServiceSupportImpl implements SyncServiceSupport {
private TimeDao timeDao;
public SyncServiceSupportImpl(Context context) {
timeDao = BrRoomDatabase.getDatabase(context).iTimeDao();
// getDatabase() from where we get DB instance.
// .. and ..
// public abstract TimeDao iTimeDao(); <= defined abstract type in RoomDatabase abstract class
}
@Override
public List<TimeEntity> getTimesEntities(String name) {
return timeDao.getServiceTimes(name);
}
}
最后...在服务中..
public class SyncService extends Service {
//..
// now, iEntities will have a List of TimeEntity objects from DB ..
// .. retrieved using @Query
private static List<TimeEntity> iEntities = new ArrayList<>();
private static SyncServiceSupportImpl iSyncService;
private static void getFromDB(String brName) {
new AsyncTask<String, Void, Void>() {
@Override
protected Void doInBackground(String... params) {
iEntities = iSyncService.getTimesEntities(params[0]);
return null;
}
@Override
protected void onPostExecute(Void agentsCount) {
}
}.execute(brName);
}
@Override
public void onCreate() {
super.onCreate();
//init service
iSyncService = new SyncServiceSupportImpl(SyncService.this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// this can be elsewhere also !..
getFromDB(myName);
}
}