Search code examples
androidandroid-contentproviderandroid-cursorloaderandroid-loadermanager

CursorLoader not refreshing on data change


I'm having a bit of a problem with android's CursorLoader. I'm using a CursorLoader to load data from my own ContentProvider. It loads the data well and keeps it on orientation changes but it does not update on data change. By the way I am using the CursorLoader that comes in the compatibility library.

I think I have done everything that the documentation and several tutorials tell me to do, but it is still not working. I have checked several posts on this site but nothig seems to fix it.

Here's is where I create the Loader:

@Override
public Loader onCreateLoader(int id, Bundle args) {
    switch (id) {            
        case TODO_EVIDENCES_LOADER_ID: {
            return new CursorLoader(this, BuilderToDoContentProvider.TODO_EVIDENCES_CONTENT_URI, null, null, new String[]{token_id}, null);
        }
    }
    return null;
}

This is the method I call on the query method on my ContentProvider:

private Cursor getToDoEvidences(String selection){
    String evidenceQuery = "SELECT " + BuilderToDoContract.Evidence.TABLE_NAME + "." + BuilderToDoContract.Evidence._ID + ", " +
            BuilderToDoContract.Evidence.TABLE_NAME + "." + BuilderToDoContract.Evidence._PATH + ", " + BuilderToDoContract.Evidence.TABLE_NAME + "." + BuilderToDoContract.Evidence._TIMESTAMP + ", " +
            BuilderToDoContract.Evidence.TABLE_NAME + "." + BuilderToDoContract.Evidence._TYPE +
            " FROM " + BuilderToDoContract.Evidence.TABLE_NAME + " WHERE " + selection;
    Cursor result = database.rawQuery(evidenceQuery, null);
    result.setNotificationUri(getContext().getContentResolver(), TODO_EVIDENCES_CONTENT_URI);
    return database.rawQuery(evidenceQuery, null);
}

This is the method I call on the delete method of my ContentProvider:

private int deleteEvidence(String[] selection) {
    int result = database.delete(BuilderToDoContract.Evidence.TABLE_NAME, BuilderToDoContract.Evidence._PATH + " = ?" , selection);
    getContext().getContentResolver().notifyChange(TODO_EVIDENCES_CONTENT_URI, null);
    return result;
}

As you can see I am creating the CursorLoader, calling setNotificationUri() on my query and calling notifyChange() on the delete method passing the same Uri, but onLoadFinished() is not getting triggered on data change. And I am not closing the cursor anywhere.

As a workaround I'm restarting the loader manually but this beats the purpose of using a CursorLoader with the LoaderManager.

I'm not using a CursorAdapter, I am putting the data I get in onLoadFinished() inside an Evidence object, then inserting this object in a list wich is the data source of a custom Adapter that is tied to a GridView. I'm doing this because I need to add other data to the Evidence object that is not present in the cursor.


Solution

  • Cursor result = database.rawQuery(evidenceQuery, null);
    result.setNotificationUri(getContext().getContentResolver(), TODO_EVIDENCES_CONTENT_URI);
    return database.rawQuery(evidenceQuery, null);
    

    You're not returning the Cursor that you called setNotificationUri on. You're returning a second rawQuery cursor. What you want is:

    Cursor result = database.rawQuery(evidenceQuery, null);
    result.setNotificationUri(getContext().getContentResolver(), TODO_EVIDENCES_CONTENT_URI);
    return result;