如何从服务中的Room数据库读取数据并监听更改?

时间:2018-06-18 18:09:36

标签: java android android-service android-room android-viewmodel

我将用户信息存储在本地房间数据库中。在活动和片段中,我使用AndroidViewModel和LiveData来监听对数据库所做的更改并更新UI。

现在,我想分析所有过去的用户数据,为将来的决策提供建议。我的建议会随着用户对数据库的每次更改而改变,因此我需要经常更新我的推荐,同时反复进行相同的计算。

我正在考虑在应用启动时启动服务,通过ViewModel和LiveData监听数据库更改并更新我的推荐(也存储在同一个数据库中)。但不知何故,服务不能

  1. 通过viewModel = ViewModelProviders.of(this).get(DataViewModel.class);
  2. 获取ViewModel
  3. 观察LiveData对象,因为它不是LifecycleOwner。
  4. 基本上我只需要读取数据库中的所有条目,分析数据并在每次数据库内容更改时更新5-10个值。

    如果不在服务中,我应该如何以及在何处进行计算?也许我陷入了错误的想法,服务不是正确的方式,所以非常感谢任何有关如何做到这一点的想法!

3 个答案:

答案 0 :(得分:3)

  

观察LiveData对象,因为它不是LifecycleOwner

observeForever()上使用LiveData,并在适当时通过removeObserver()手动注销(服务onDestroy(),如果不早的话)。

请记住,此处适用标准服务限制(例如,除非它们是前台服务,否则它们在Android 8.0+上运行约1分钟),因此您可能仍然需要考虑其他方法。

答案 1 :(得分:1)

我最终使用了Service并按如下方式解决了我的问题:

在我的onCreate的{​​{1}}方法中,将Application object绑定到它:

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获得了ViewModel的实例

AndroidViewModelFactory

我可以像这样通过MyViewModel myViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(MyViewModel.class); 观察从ViewModel获取的LiveData

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); 中的LiveData引用中删除观察者(这就是为什么我对Observer对象保留本地引用的原因):

onDestroy

谢谢大家!

答案 2 :(得分:1)

实体没有任何变化。

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

接口类

public interface SyncServiceSupport {
    List<TimeEntity> getTimesEntities(String brName);
}

一个实现类。

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

}