RecyclerView使用Room和PagingListAdapter向下滚动数据更新

时间:2019-02-02 02:44:29

标签: android android-recyclerview android-room android-architecture-components android-paging

我创建了一个示例项目,以显示我在使用RecyclerView,Room和Paging时遇到的问题,即 RecyclerView意外地向下滚动数据更新

https://github.com/HappyPeng2x/RoomRecyclerViewExample

该应用程序有一个Room数据库,我正在使用从PagedListAdapter派生的适配器在RecyclerView中显示其值。

将观察到查询,如下面的代码所示,以便适配器的每次更新都会反映该表。

   PagedList.Config plConfig =
            new PagedList.Config.Builder().setEnablePlaceholders(false)
            .setPrefetchDistance(10)
            .setPageSize(20).build();

    new LivePagedListBuilder<>
            (mDB.getMyDao().getAllPaged(), plConfig)
            .build()
            .observe(this, new Observer<PagedList<MyEntry>>() {
                @Override
                public void onChanged(PagedList<MyEntry> myList) {
                    adapter.submitList(myList);
                }
            });

为了进行测试,我在表中填充了1000个键/值对。键从1开始到1 000结束,并且所有值都以INITIAL初始化。

在每个显示的元素中都包含一个切换按钮;单击它会将值从INITIAL切换为FINAL,然后反转。

在第155个元素上按下切换按钮时,显示的值从INITIAL更改为FINAL,没有任何问题。

在243rd元素上执行相同操作时,按下按钮会使RecyclerView向下滚动这是不期望的

每次在此位置上按下一个按钮时,都会重复出现此问题。

我拍摄了视频,以便可以观察到该问题。

https://github.com/HappyPeng2x/RoomRecyclerViewExample/blob/master/videos/device-2019-02-02-105434.webm

我一直在这个问题上苦苦挣扎,并且感到有点as愧,因为这似乎是对Architecture Components的基本使用,因此我非常乐意获得任何帮助。

3 个答案:

答案 0 :(得分:2)

此问题是一个错误,已由Google解决,并且该修复程序应包含在下一版Paging中,但遗憾的是尚未发生。

问题跟踪器中的URL是https://issuetracker.google.com/issues/123834703-但是,由于必须记录下来才能看到它,因此我将在此处复制主要元素。

正如开发人员所解释的那样,问题在于该库通常会在最后访问的位置 附近触发初始加载,但是如果禁用了占位符,则会绕过此逻辑,从而导致加载最后访问的位置。由于此位置通常是RecyclerView绑定的最后部分脱离屏幕的项目,因此这意味着屏幕上的大多数项目在初始加载时就丢失了,只能在以后分页。

尚未发布包含此修复程序的发行版,您必须使用开发版本,但是您也可以在https://github.com/HappyPeng2x/RoomRecyclerViewExample上添加开发人员为我的示例应用建议的解决方法。

1)将以下类添加到MainActivity.java:

static class RoomFactoryWrapper<T> extends DataSource.Factory<Integer, T> {
    final DataSource.Factory<Integer, T> m_wrappedFactory;

    RoomFactoryWrapper(@NonNull Factory<Integer, T> wrappedFactory) {
        m_wrappedFactory = wrappedFactory;
    }

    @NonNull
    @Override
    public DataSource<Integer, T> create() {
        return new DataSourceWrapper<>((PositionalDataSource<T>) m_wrappedFactory.create());
    }

    static class DataSourceWrapper<T> extends PositionalDataSource<T> {
        final PositionalDataSource<T> m_wrappedSource;

        DataSourceWrapper(PositionalDataSource<T> wrappedSource) {
            m_wrappedSource = wrappedSource;
        }

        @Override
        public void addInvalidatedCallback(@NonNull InvalidatedCallback onInvalidatedCallback) {
            m_wrappedSource.addInvalidatedCallback(onInvalidatedCallback);
        }

        @Override
        public void removeInvalidatedCallback(
            @NonNull InvalidatedCallback onInvalidatedCallback) {
            m_wrappedSource.removeInvalidatedCallback(onInvalidatedCallback);
        }

        @Override
        public void invalidate() {
            m_wrappedSource.invalidate();
        }

        @Override
        public boolean isInvalid() {
            return m_wrappedSource.isInvalid();
        }

        @Override
        public void loadInitial(@NonNull LoadInitialParams params,
            @NonNull LoadInitialCallback<T> callback) {
            // Workaround for paging bug: https://issuetracker.google.com/issues/123834703
            // edit initial load position to start 1/2 load ahead of requested position
            int newStartPos = params.placeholdersEnabled
                ? params.requestedStartPosition
                : Math.max(0, params.requestedStartPosition - (params.requestedLoadSize / 2));
            m_wrappedSource.loadInitial(new LoadInitialParams(
                newStartPos,
                params.requestedLoadSize,
                params.pageSize,
                params.placeholdersEnabled
            ), callback);
        }

        @Override
        public void loadRange(@NonNull LoadRangeParams params,
            @NonNull LoadRangeCallback<T> callback) {
            m_wrappedSource.loadRange(params, callback);
        }
    }
}

2)在dataSourceFactory上使用包装器:

    new LivePagedListBuilder<>
            (new RoomFactoryWrapper<>(mDB.getMyDao().getAllPaged()), plConfig)

答案 1 :(得分:0)

尽管我不确定,但这可能会对您有所帮助。

"principalId": "$authenticated"

答案 2 :(得分:0)

我设置了此配置,效果很好。

那里的主要物品是setMaxSize(pageSize + 2 * prefetchDistance) 尽可能降低价值。

val config = PagedList.Config.Builder()
            .setEnablePlaceholders(true)
            .setMaxSize(pageSize + 2 * prefetchDistance)
            .setPrefetchDistance(prefetchDistance)
            .setPageSize(pageSize)
            .build()`

我尝试不使用它,RecyclerView的外观也不错,但PagedListAdapter的元素绑定错误。