如何观察数据库的变化以更新 LiveData

Posted

技术标签:

【中文标题】如何观察数据库的变化以更新 LiveData【英文标题】:How to observe changes in database in order to update LiveData 【发布时间】:2019-03-18 01:07:13 【问题描述】:

我正在将应用程序从带有 CallbacksLoaderManager 迁移到使用 ViewModelLiveData 的实现。我想继续使用现有的SQLiteDatabase

主要实现工作正常。 Activity 实例化 ViewModel 并创建一个 Observer,如果它观察到位于 ViewModel 中的 MutableLiveData 的变化,它会更新 ViewViewModel 通过使用ContentProvider 的查询从SQLiteDatabase 获取数据(光标)。

但我还有其他可以更改数据库的活动,而 MainActivity 已停止但未销毁。还有一个后台服务可以在MainActivity 处于前台时更改数据库。

其他活动和后台服务可以更改数据库中的值,因此会对ViewModel 中的MutableLiveData 产生影响。

我的问题是:如何观察SQLiteDatabase 的变化以更新LiveData

这是MainActivity的简化版:

public class MainActivity extends AppCompatActivity 
    private DrawerAdapter mDrawerAdapter;
    HomeActivityViewModel homeActivityViewModel;

    private Observer<Cursor> leftDrawerLiveDataObserver = new Observer<Cursor>() 
        @Override
        public void onChanged(@Nullable Cursor cursor) 
            if (cursor != null && cursor.moveToFirst())  // Do we have a non-empty cursor?
                mDrawerAdapter.setCursor(cursor);
            
        
    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        homeActivityViewModel = ViewModelProviders.of(this).get(HomeActivityViewModel.class);
        homeActivityViewModel.getLiveData().observe(this, leftDrawerLiveDataObserver);
        homeActivityViewModel.updateLiveData(); //,LEFT_DRAWER_LIVEDATA_ID);
    

    @Override
    protected void onResume()  // update the LiveData on Resume
        super.onResume();
        homeActivityViewModel.updateLiveData();
    

这是我的ViewModel

public class HomeActivityViewModel extends androidViewModel 

    public HomeActivityViewModel(Application application) 
        super(application);
    

    @NonNull
    private final MutableLiveData<Integer> updateCookie = new MutableLiveData<>();

    @NonNull
    private final LiveData<Cursor> cursorLeftDrawer =
            Transformations.switchMap(updateCookie,
                    new Function<Integer, LiveData<Cursor>>() 
                        private QueryHandler mQueryHandler;

                        @Override
                        public LiveData<Cursor> apply(Integer input) 
                            mQueryHandler = new QueryHandler(getApplication().getContentResolver());
                            MutableLiveData<Cursor> cursorMutableLiveData = new MutableLiveData<>();
                            mQueryHandler.startQuery(ID, cursorMutableLiveData, URI,
                                new String[]FeedData.ID, FeedData.URL,
                                null,null,null
                            );
                            return cursorMutableLiveData;
                        
                    
            );

    // By changing the value of the updateCookie, LiveData gets refreshed through the Observer.
    void updateLiveData() 
        Integer x = updateCookie.getValue();
        int y = (x != null) ? Math.abs(x -1) : 1 ;
        updateCookie.setValue(y);
    

    @NonNull
    LiveData<Cursor> getLiveData() 
        return cursorLeftDrawer;
    

    /**
     * Inner class to perform a query on a background thread.
     * When the query is completed, the result is handled in onQueryComplete
     */
    private static class QueryHandler extends AsyncQueryHandler 
        QueryHandler(ContentResolver cr) 
            super(cr);
        
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) 
            MutableLiveData<Cursor> cursorMutableLiveData = (MutableLiveData<Cursor>) cookie;
                             cursorMutableLiveData.setValue(cursor);

        
    


【问题讨论】:

可能使用developer.android.com/reference/android/database/…(并在内容解析器中通知!***.com/questions/24465999/…) 这也许是个不错的方法。我会进一步研究一下。谢谢! 我实现了一个简单的ContentObserver,它就像一个魅力。谢谢你的帮助! @zapl 【参考方案1】:

也许你应该看看Room。 Room 数据库在后台使用 SQLite,并在数据库发生任何更改时自动通知您的 LiveData 对象。因此,您永远不需要担心查询和游标等。 看看这个tutorial!

【讨论】:

谢谢。我一定会调查Room。不幸的是,这是一个具有相当复杂的内容提供者和数据库的现有应用程序。 Android 弃用了CursorLoaders(顺便说一句,它工作得非常好),所以我想先迁移到 ViewModels 并保持应用程序正常运行。之后,我可以采取措施实现Room 好吧,在这种情况下 ContentObserver 可能会更好:)

以上是关于如何观察数据库的变化以更新 LiveData的主要内容,如果未能解决你的问题,请参考以下文章

Android Room LiveData观察器未更新

LiveData详解

LiveData,是不是可以观察特定值

Android jetpack架构组件LiveData实战与源码解析

Room:来自 Dao 的 LiveData 将在每次更新时触发 Observer.onChanged,即使 LiveData 值没有变化

Android-LiveData原理解析