I have an activity ActitvityA that holds a listview populated by a CursorLoader. I want to switch to ActivityB and change some data and see those changes reflected in listview in ActivityA.
public class ActivityA implements LoaderManager.LoaderCallbacks<Cursor>
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
mCursorAdapter = new MyCursorAdapter(
this,
R.layout.my_list_item,
null,
0 );
}
.
.
.
/** Implementation of LoaderManager.LoaderCallbacks<Cursor> methods */
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle arg1) {
CursorLoader result;
switch ( loaderId ) {
case LOADER_ID:
/* Rename v _id is required for adapter to work */
/* Use of builtin ROWID http://www.sqlite.org/autoinc.html */
String[] projection = {
DBHelper.COLUMN_ID + " AS _id", //http://www.sqlite.org/autoinc.html
DBHelper.COLUMN_NAME // columns in select
}
result = new CursorLoader( ActivityA.this,
MyContentProvider.CONTENT_URI,
projection,
null,
new String[] {},
DBHelper.COLUMN_NAME + " ASC");
break;
default: throw new IllegalArgumentException("Loader id has an unexpectd value.");
}
return result;
}
/** Implementation of LoaderManager.LoaderCallbacks<Cursor> methods */
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
switch (loader.getId()) {
case LOADER_ID:
mCursorAdapter.swapCursor(cursor);
break;
default: throw new IllegalArgumentException("Loader has an unexpected id.");
}
}
.
.
.
}
From ActivityA I switch to ActivityB where I change the underlying data.
// insert record into table TABLE_NAME
ContentValues values = new ContentValues();
values.put(DBHelper.COLUMN_NAME, someValue);
context.getContentResolver().insert( MyContentProvider.CONTENT_URI, values);
The details of MyContentProvider:
public class MyContentProvider extends ContentProvider {
.
.
.
@Override
public Uri insert(Uri uri, ContentValues values) {
int uriCode = sURIMatcher.match(uri);
SQLiteDatabase database = DBHelper.getInstance().getWritableDatabase();
long id = 0;
switch (uriType) {
case URI_CODE:
id = database.insertWithOnConflict(DBHelper.TABLE_FAVORITE, null, values,SQLiteDatabase.CONFLICT_REPLACE);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null); // I call the notifyChange with correct uri
return ContentUris.withAppendedId(uri, id);
}
@Override
public Cursor query(Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
// Using SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
int uriCode = sURIMatcher.match(uri);
switch (uriCode) {
case URI_CODE:
// Set the table
queryBuilder.setTables(DBHelper.TABLE_NAME);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase database = DBHelper.getInstance().getWritableDatabase();
Cursor cursor = queryBuilder.query( database, projection, selection, selectionArgs, null, null, sortOrder);
// Make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
}
As far as my knowledge goes this should be sufficient. But it does not work. Upon returning to ActivityA the listview is unchanged.
I have followed things with debugger and this is what happens.
First visit ActivityA, the methods that are called in that order
MyContentProvider.query()
ActivityA.onLoadFinished()
The listview displays the correct values. And now I switch to activityB and change the data
MyContentProvider.insert() // this one calls getContext().getContentResolver().notifyChange(uri, null);
MyContentProvider.query()
//As we can see the MyContentProvider.query is executed. I guess in response to notifyChange().
// What I found puzzling why now, when ActivityB is still active ?
Return to ActivityA
!!! ActivityA.onLoadFinished() is not called
I have read anything I could about this, took a close look at a lot of stackoverflow questions yet all those question/answers revolve around setNotificationUri() and notifyChangeCombo() which I implemented. Why does this not work across activities?
If for example force refresh in ActivityA.onResume() with
getContentResolver().notifyChange(MyContentProvider.CONTENT_URI, null, false);
then it refreshes the list view. But that would force refresh on every resume regardless if data was changed or not.
initLoader
? – SteerageLog.d
inLoaderManager.LoaderCallbacks<Cursor>
methods and inonCreate
where you callinitLoader
– LorollagetSupportLoaderManager
instead ofgetLoaderManager
and remove the last param ofSimpleCursorAdapter
ctor and of course useFragmentActivity
as a base – LorollaSQLiteCursor
notMatrixCursor
– Lorolla