Cursorloader does not update when the underlying data changes

I have a content provider, a content recognizer, and a cursor downloader. The loader is used to indirectly populate the list (i.e., not a simple cursor adapter, but an array adapter, since I need to use the cursor results to collect other data).

When I change the underlying data, the list view is not populated again, since the onLoadFinished(Loader<Cursor>, Cursor) not called.

As expected, while I am writing this, there are many questions on this subject. e.g. CursorLoader does not update after data change

And all the questions point to two things:

  • In the query () method of your content provider, you must inform the cursor about a'la notifications

c.setNotificationUri(getContext().getContentResolver(), uri);

  • In the insert / update / delete method of your content provider, you must notify the URI of this:

getContext().getContentResolver().notifyChange(uri, null);

I do these things.

I also DO NOT close the cursors that return to me.

Please note that my content provider lives in a separate application (think of it as a content provider application - without the main launch activity). The APK file is com.example.provider, and com.example.app calls (in the content resolver) through the content URI: //com.example.provider/table, etc. The content resolver (dbhelper) is located in the library project. (com.example.appdb) that the action refers to. (Thus, several projects can use dbhelper via links, and all content providers are installed through one APK)

I turned on debugging in the bootloader manager and see where I force the data to be updated after changing the data (i.e. restarting the bootloader and marking the previous one as inactive), but nothing that says that something happens automatically is more likely in response on my strength to freshen up.

Any ideas why my bootloader is not updating?

- UPDATE -

The loader creates:

 Log.d(TAG, "onCreateLoader ID: " + loaderID); // typically a switch on the loader ID, and then return dbHelper.getfoo() 

Where getfoo () returns the cursor loader via:

return new CursorLoader(context, FOO_URI, foo_Fields, foo_query, foo_argArray, foo_sort );

Loader Finish takes the cursor and fills the table (and does some processing) - there’s nothing complicated.

 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { Log.d(TAG, "onLoadFinished id: " + loader.getId()); // switch on loader ID .. FillTable(cursor, (FooAdapter) foo_info.listview.getAdapter(); 

Loader Reset clears the table.

 public void onLoaderReset(Loader<Cursor> loader) { Log.d(TAG, "onLoaderReset id: " + loader.getId()); // normally a switch on loader ID ((FooAdapter)foo_info.listview.getAdapter()).clear(); 

The content provider does:

 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor cursor; SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); SQLiteDatabase db = dbHelper.getReadableDatabase(); switch (sUriMatcher.match(uri)) { case FOO: qb.setTables(FOO); qb.setProjectionMap(FooProjectionMap); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } 

Then insert / update similarly:

 public Uri insert(Uri uri, ContentValues initialValues) { ContentValues values; if (initialValues != null) { values = new ContentValues(initialValues); } else { values = new ContentValues(); } String tableName; Uri contentUri; switch (sUriMatcher.match(uri)) { case FOO: tableName = FOOTABLE; contentUri = FOO_URI; break; default: throw new IllegalArgumentException("Unknown URI " + uri); } SQLiteDatabase db = dbHelper.getWritableDatabase(); long rowId = db.insert(tableName, null, values); if (rowId > 0) { Uri objUri = ContentUris.withAppendedId(contentUri, rowId); getContext().getContentResolver().notifyChange(objUri, null); return objUri; } throw new SQLException("Failed to insert row into " + uri); } 
+6
source share
3 answers

I see that you are not calling swapCursor or changeCursor in onLoadFinished and onLoaderReset. You need to do this for your adapter in order to access the data loaded in the new cursor.

in onLoadFinished, call something like:

 mAdapter.swapCursor(cursor) 

In onLoaderReset, call this to remove references to the old cursor:

 mAdapter.swapCursor(null) 

Where mAdapter is your listView adapter.

Additional information: http://developer.android.com/guide/components/loaders.html#onLoadFinished

+2
source

So, for those who watch this and have this problem:

Make sure that the URI you pointed to is the same as the URI you pointed to.

In my case, I used a different URI for the query than was used in another code that changed the base table. There was no easy fix for working with notification, so I continued to reset the bootloader in OnResume () as a solution.

+2
source

This is not a direct answer to this particular problem, but may help others in a similar situation. In my case, I had a join, and although I used the full name tablename.column in the projection and query. In any case, this led to invalid identifier values. Therefore, be sure to check the syntax of ContentProvider or SQL.

+1
source

Source: https://habr.com/ru/post/947161/


All Articles