I am migrating an app from a LoaderManager
with Callbacks
to an implementation using ViewModel
and LiveData
. I would like to keep using the existing SQLiteDatabase
.
The main implementation works OK. The Activity
instantiates the ViewModel
and creates an Observer
which updates the View
if it observes changes in the MutableLiveData
that lives in the ViewModel
. The ViewModel
gets it data (cursor) from the SQLiteDatabase
through a query using a ContentProvider
.
But I have other activities that can make changes to the database, while MainActivity
is stopped but not destroyed. There is also a background service that can make changes to the database while the MainActivity
is on the foreground.
Other activities and the background service can change values in the database and therefore can have an effect to the MutableLiveData
in the ViewModel
.
My question is: How to observe changes in the SQLiteDatabase
in order to update LiveData
?
This is a simplified version of 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();
}
}
This is my 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);
}
}
}