首先让我来描述一下我的情况:我收到了填充RecyclerView
的类别列表。此列表中的每个View
都是某种窗口小部件,最常见的是另一个列表(水平RecyclerView
)和一些新闻(也是从JSON解析)。
我将所有内容保存在ContentProvider
和SQLiteDatabase
(带帮助程序)中,其中包含两个表 - 用于类别和新闻(每个都有类别ID键)。所以我使用Loader
为每个小部件加载数据库中的数据,或者如果丢失我正在下载正确的数据并插入到数据库中。然后加载器自动刷新列表,提供新光标。
屏幕上可能会出现两个(或更多)带有新闻的水平列表。这些列表中的每一个都在这里注册自己的Loader
:
loaderManager.initLoader(getWidgetCategory().getCategoryID(), null, getLoader());
在getLoader();
下我们有相同的Loader
(对于有新闻的小部件),如下所示:
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);
}
}
问题是:当我从一个类别下载并插入数据库新闻时,所有Loader
都会触发刷新列表,这对性能非常不利......例如 - 有两个水平列表随着屏幕上的新闻,我们滚动了一下,另一个(第三个)即将到来。它没有任何消息,因此后台任务正在下载它们并插入到db中,然后LoaderManager
触发Loader
第三个小部件。但不仅......上面两个列表中附加的Loaders
正在激活刷新自己的列表。
我假设同一个CONTENT_URI
存在问题,可能是CursorLoader
构造函数中的其他参数。其中唯一的变化(对于每个新闻水平列表小部件)是具有不同类别ID的WHERE
子句,并且所有Loader
s都从同一个db表获取内容。我怎样才能为小部件只发送一个Loader
,下载/插入新闻?请注意,已注册的加载程序的ID和WHERE
选择是相同的......
就像我写的那样,可能会有不同类型的小部件(还有列表,但没有新闻),这些小部件是从其他表中填充的,而Loader
不是用新闻Loader
触发的。我假设如果我只获得只有文本小部件(也是共享数据库表)的类别列表,下载其中一个小部件的文本将触发所有`Loader's并重绘其他小部件。
修改
在其他简短的字词中:在我的自定义ContentProvider
中,我覆盖了query
方法,其中包含以下行:
@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;
}
并且它通过Loader
通知所有观察uri
。我有几个列表(实际上这些都是RecyclerView
s),这些列表正在使用来自一个URI的数据,但是将自定义选择参数传递给每个CursorLoader
。但是URI对于所有人都是通用的,因此所有加载器都会得到通知,我只想通知这一个,它会触发数据库活动。我只想通知一个具有已知ID的Loader
,这也会传递给query
内的selectionArgs
方法。是的,我知道在query
内这可能是不可能的,但也许是另一种方式?用于通知Loader
不仅仅是通过其URI
答案 0 :(得分:1)
URI对所有人都是通用的,因此所有加载器都会得到通知,我只想通知这个,这会激发数据库活动。
最简单的解决方法是创建一个URI模式,其中每个类别的URI都不同,因此当您调用Cursor.setNoficationUri()
时,每个游标(最终,每个加载器)将仅接收与其相关的数据的ContentChanged通知。 。
没有办法关闭ContentObserver
上的CursorLoader
,所以如果你绝对肯定不能有不同的URI,那么我唯一可以建议的是写{{1}知道何时在游标上注册和注销其观察者的子类。
(从早期的回答编辑)