简体   繁体   English

如何使用架构组件分页库停止在回收站视图上闪烁

[英]How to stop blinking on recycler view with architecture components paging library

I have a chat-like activity where I am using a RecyclerView with a PagedListAdaper to load a bunch of messages.我有一个类似聊天的活动,我使用带有 PagedListAdaper 的 RecyclerView 来加载一堆消息。 I'm using a PositionalDataSource to load the data.我正在使用 PositionalDataSource 来加载数据。 The loading it's self works fine but when I send a message, I invalidate my datasource and the list gets remade.加载它自己工作正常,但是当我发送消息时,我使我的数据源无效并且列表被重新制作。 My problem is that it blinks when it does that :我的问题是当它这样做时它会闪烁

这是它的样子

I have tried adding setHasStableIds(true) and overriding getItemId which would work on a simple adapter but it doesn't seem to work here.我已经尝试添加 setHasStableIds(true) 并覆盖 getItemId ,它可以在一个简单的适配器上工作,但它似乎在这里不起作用。 I also cannot seem to be able to just add an item to the getCurrentList() because it's not supported.我似乎也无法将一个项目添加到 getCurrentList() 中,因为它不受支持。 Also, I'm not using a database, just making requests to a server.另外,我没有使用数据库,只是向服务器发出请求。

So my questions are, is there a better way of doing this besides invalidating the data source?所以我的问题是,除了使数据源无效之外,还有更好的方法吗? Is there a way to stop the list from blinking when sending a message?有没有办法在发送消息时阻止列表闪烁? Or is this library just not suited for my chat activity?还是这个库不适合我的聊天活动?

Edit :编辑

my diff callback我的差异回调

private val DIFF_CALLBACK: DiffCallback<MessageModel> = object : DiffCallback<MessageModel>() {
        override fun areItemsTheSame(@NonNull oldMessage: MessageModel, @NonNull newMessage: MessageModel) =
                oldMessage.id == newMessage.id


        override fun areContentsTheSame(@NonNull oldMessage: MessageModel, @NonNull newMessage: MessageModel) =
                oldMessage.equals(newMessage)
    }

Edit2 I fixed it : Edit2 我修复了它

So I managed to fix it by using PagedListAdapterHelper and setting it's list after the items loaded:所以我设法通过使用 PagedListAdapterHelper 并在加载项目后设置它的列表来修复它:

private var mHelper: PagedListAdapterHelper<MessageModel>? = null

init {
    mHelper = PagedListAdapterHelper(this, DIFF_CALLBACK)
    setHasStableIds(true)
}
fun setList(pagedList: PagedList<MessageModel>) {
    pagedList.addWeakCallback(pagedList.snapshot(), object:PagedList.Callback() {
        override fun onChanged(position: Int, count: Int) {

        }

        override fun onInserted(position: Int, count: Int) {
            mHelper?.setList(pagedList)
        }

        override fun onRemoved(position: Int, count: Int) {

        }

    })
}

Short answer: make sure to call the callback of PositionalDataSource<T>.loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<T> callback) synchronously in loadInitial without wrapping it in some kind of asynchronous success handler.简短的回答:请确保调用的callbackPositionalDataSource<T>.loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<T> callback)同步在loadInitial没有某种异步成功处理程序的包装它。

Explanation:说明:

Blinking can be caused by asynchronous loads in your initial load ie in PositionalDataSource<T>.loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<T> callback) .闪烁可能是由初始加载中的异步加载引起的,即在PositionalDataSource<T>.loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<T> callback)

The following will happen when you do so:这样做时会发生以下情况:

Your data source gets invalidated which leads to the creation of a new PagedList (when created with LivePagedListBuilder ).您的数据源失效,导致创建新的PagedList (使用LivePagedListBuilder创建时)。 This newly created paged list will be passed to your adapter but it is still empty because you didn't call the callback directly in your initial load.这个新创建的分页列表将传递给您的适配器,但它仍然是空的,因为您没有在初始加载时直接调用回调。 This will lead to an empty list for as long as it takes for your callback to be called.只要您的回调被调用,这将导致一个空列表。 This ultimately results in a flicker effect.这最终导致闪烁效果。

PagedListAdapterHelper deprecated in Paging Component so we should use AsyncPagedListDiffer instead of it. PagedListAdapterHelper 在 Paging Component 中已弃用,因此我们应该使用AsyncPagedListDiffer而不是它。

Code example:代码示例:

    import android.arch.paging.AsyncPagedListDiffer;
    import android.arch.paging.PagedList;
    import android.arch.paging.PagedListAdapter;
    import android.support.annotation.NonNull;
    import android.support.v7.util.DiffUtil;
    import android.view.LayoutInflater;
    import android.view.ViewGroup;


    public class PagedItemsArrayAdapter extends PagedListAdapter<Item, MyViewHolder> {

            private final AsyncPagedListDiffer<Item> mDiffer;

            public PagedItemsArrayAdapter() {
                super(DIFF_CALLBACK);
                mDiffer = new AsyncPagedListDiffer<>(this, DIFF_CALLBACK);
                setHasStableIds(true);
            }

            @Override
            public long getItemId(int position) {
               Item item = mDiffer.getItem(position);
               return item.id;
            }

            @Override
            public int getItemCount() {
                return mDiffer.getItemCount();
            }

            @Override
            public void submitList(PagedList<Item> pagedList) {

                pagedList.addWeakCallback(pagedList.snapshot(), new PagedList.Callback() {
                    @Override
                    public void onChanged(int position, int count) {
                    }

                    @Override
                    public void onInserted(int position, int count) {
                        mDiffer.submitList(pagedList);
                    }

                    @Override
                    public void onRemoved(int position, int count) {

                    }
                });

            }


            @Override
            public void onBindViewHolder(@NonNull MyViewHolder viewHolder, int position) {
                   Item item = mDiffer.getItem(position);
                   viewHolder.onBind(item); 
            }

            private static DiffUtil.ItemCallback<Item> DIFF_CALLBACK = new DiffUtil.ItemCallback<Item>() {
                @Override
                public boolean areItemsTheSame(@NonNull Item oldItem, @NonNull Item newItem) {
                    return oldItem.getId() == newItem.getId();
                }

                @Override
                public boolean areContentsTheSame(@NonNull Item oldItem, @NonNull Item newItem) {
                    return oldItem.equals(newItem);
                }
            };

您可以禁用项目动画。

mRecyclerView.setItemAnimator(null);

you should use sync in loadInitial and loadAfter , ie:您应该在loadInitialloadAfter使用同步,即:

mLoadState.postValue(NetworkState.Loading);
try {
    mLoadState.postValue(NetworkState.DONE);
    ResultMessage<List<Achievement>> info = call.execute().body();
    if (info != null && info.isSuccess()) {
        List<Achievement> list = info.getData();
        callback.onResult(list, null, FIRST_PAGE + 1);
    }
} catch (IOException e) {
    mLoadState.postValue(NetworkState.ERROR);
    mRetry.postValue(() -> loadInitial(params, callback));
    Log.d(TAG, "fail!");
}

We are using paging library 3 with room .我们正在使用带有room paging library 3 We were getting flickering, blinking and scrolling effects after we wrote some next page data on database.在我们在数据库上写了一些下一页数据后,我们得到了闪烁、闪烁和滚动的效果。 Because we set the PagingConfig 's initialLoadSize different than pageSize .因为我们将PagingConfiginitialLoadSize设置为与pageSize不同。 We have started to use same value for both of them and our problem has been fixed.我们已经开始对它们使用相同的值,我们的问题已经解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM