Reputation: 19233
Firstly let me describe my case: I'm receiving list of categories which populate RecyclerView
. Each View
on this list is some kind of widget and most common is another list (horizontal RecyclerView
) with some news (also parsed from JSON).
I'm keeping all stuff in ContentProvider
and SQLiteDatabase
(with helper), which contains two tables - for categories and for news (each have category id key). So I'm using Loader
for each widget to load data from database or if missing I'm downloading proper data and inserting into db. And then loader automatically refresh list delivering new cursor.
At once there may be present on the screen two (or more) horizontal lists with news. Each of these lists is registering own Loader
like here:
loaderManager.initLoader(getWidgetCategory().getCategoryID(), null, getLoader());
under getLoader();
we have same Loader
(for widgets with news) like below:
private class NewsLoader implements LoaderManager.LoaderCallbacks<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
return new CursorLoader(getContext(),
CustomContract.News.CONTENT_URI,
CustomContract.News.PROJECTION_ALL,
CustomContract.News.KEY_CATEGORY_ID+"=?",
new String[]{String.valueOf(getWidgetCategory().getCategoryID())},
CustomContract.News.ORDER_BY_DEFAULT
);
}
@Override
public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
if (data.getCount()>=15) {
swapCursor(data);
displayContent();
}
}
@Override
public void onLoaderReset(final Loader<Cursor> loader) {
swapCursor(null);
}
}
And the problem is: when I download and insert to database news from only one category all the Loader
s are firing refreshing lists and it is really bad for performance... For example - there are two horizontal lists with news on the screen, we are scrolling a bit down and another (third) is coming. It doesn't have any news so background task is downloading them and inserting into db and then LoaderManager
fires Loader
for third widget. BUT not only... Also Loaders
attached to two lists above are firing refreshing own lists.
I'm assuming there is a problem with same CONTENT_URI
, maybe other params in CursorLoader
constructor. The only change in there (for every news horizontal list widget) is WHERE
clause with different category id and all Loader
s are getting content from the same db table. How can I keep firing only one Loader
for widget, which downloaded/inserted news? Note that id of registered loader and WHERE
selection are the same...
Like I wrote there might be different types of widgets (and also lists, but not with news), which are populated from other tables and their Loader
s are not firing with news Loader
s. I'm assuming that if I get list of categories with only just-text-widgets (also shared db table) downloading text for one of the widgets will fire all `Loader's and redraw other widgets.
edit:
In other, short words: in my custom ContentProvider
I have overriden query
method, which contains line:
@Override
public Cursor query(
final Uri uri,
final String[] projection,
final String selection,
final String[] selectionArgs,
String sortOrder
) {
//selection, etc.
//newly created cursor from selection above
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
and it's notifying all observing Loader
s with passed uri
. I have few lists (does not matter in fact that these are RecyclerView
s) which are consuming data from one URI, but are passing custom selection param to each CursorLoader
. But URI is common for all so all loaders are notified and I want to notify only this one, which fired database activity. I want to notify only one Loader
with known id, which is also passed to query
method inside selectionArgs
. Yeah, I know that this might be impossible inside query
, but maybe another way? For notifying Loader
s not only by their URI
Upvotes: 0
Views: 170
Reputation: 30985
URI is common for all so all loaders are notified and I want to notify only this one, which fired database activity.
The easiest fix is to create a URI pattern where the URI is different for each category, so when you call Cursor.setNoficationUri()
each cursor (and ultimately, each loader) will only receive ContentChanged notifications for the data it's concerned with.
There's no way to turn off the ContentObserver
on a CursorLoader
, so if you absolutely positively can't have different URIs, then the only other thing I can suggest is to write a Loader<Cursor>
subclass that knows when to register and unregister its observer on the cursor.
(Edited from earlier answer)
Upvotes: 1