LoaderManager同时触发所有Loaders

时间:2015-10-30 08:07:43

标签: android android-loadermanager android-loader

首先让我来描述一下我的情况:我收到了填充RecyclerView的类别列表。此列表中的每个View都是某种窗口小部件,最常见的是另一个列表(水平RecyclerView)和一些新闻(也是从JSON解析)。

我将所有内容保存在ContentProviderSQLiteDatabase(带帮助程序)中,其中包含两个表 - 用于类别和新闻(每个都有类别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

1 个答案:

答案 0 :(得分:1)

  

URI对所有人都是通用的,因此所有加载器都会得到通知,我只想通知这个,这会激发数据库活动。

最简单的解决方法是创建一个URI模式,其中每个类别的URI都不同,因此当您调用Cursor.setNoficationUri()时,每个游标(最终,每个加载器)将仅接收与其相关的数据的ContentChanged通知。 。

没有办法关闭ContentObserver上的CursorLoader,所以如果你绝对肯定不能有不同的URI,那么我唯一可以建议的是写{{1}知道何时在游标上注册和注销其观察者的子类。

(从早期的回答编辑)