使用DiffUtil,如何在更新NestedScrollView中包含的recyclerView时防止阻塞主线程? [英] Using DiffUtil, How to prevent blocking the main thread when updating the recyclerView contained in a NestedScrollView?

本文介绍了使用DiffUtil,如何在更新NestedScrollView中包含的recyclerView时防止阻塞主线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在后台线程中对我的recyclerView进行审核,而没有任何成功.

I'm trying to udate my recyclerView in background Thread without any succes.

更新recyclerView仍会阻塞主线程.

Updating the recyclerView still block the main thread.

这是我的适配器:

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.PostViewHolder> {
    
        private List<PostItems> postList;
        private Context context;
        private Queue<List<PostItems>> pendingUpdates = new ArrayDeque<>();
    
        PostAdapter(List<PostItems> postList, Context context) {
            this.postList = postList;
            this.context = context;
        }
    
        @NonNull
        @Override
        public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_view_wall_post, parent, false);
            return new PostViewHolder(v);
        }
    
        @Override
        public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
            PostItems post_items = postList.get(position);
                 ...
                 ...
                 .........
                 ...
                 ...
        }
    
        @Override
        public int getItemCount() {
            return postList.size();
        }

        @Override
        public int getItemViewType(int position) {
            return position;
        }

        static class PostViewHolder extends RecyclerView.ViewHolder {
            PostViewHolder(@NonNull View itemView) {
                super(itemView);
                ...
                ...
                .........
                ...
                ...
            }
        }
    }


/*
* here the background Thread
* 
*/

// The Fragment or Activity will call this method
    // when new data becomes available
    public void updateItems(final List<PostItems> newItems) {
        pendingUpdates.add(newItems);
        if (pendingUpdates.size() > 1) {
            return;
        }
        updateItemsInternal(newItems);
    }
    // This method does the heavy lifting of
    // pushing the work to the background thread
    void updateItemsInternal(final List<PostItems> newItems) {
        final List<PostItems> oldItems = new ArrayList<>(this.postList);
        final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                final DiffUtil.DiffResult diffResult =
                        DiffUtil.calculateDiff(new DiffCb(oldItems, newItems));
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        applyDiffResult(newItems, diffResult);
                    }
                });
            }
        }).start();
    }
    // This method is called when the background work is done
    protected void applyDiffResult(List<PostItems> newItems,
                                   DiffUtil.DiffResult diffResult) {
        pendingUpdates.remove();
        dispatchUpdates(newItems, diffResult);
        if (pendingUpdates.size() > 0) {
            updateItemsInternal(pendingUpdates.peek());
        }
    }
    // This method does the work of actually updating
    // the backing data and notifying the adapter
    protected void dispatchUpdates(List<PostItems> newItems,
                                   DiffUtil.DiffResult diffResult) {
        diffResult.dispatchUpdatesTo(this);
        postList.clear();
        postList.addAll(newItems);
        Toast.makeText(context, "b"+postList.size(), Toast.LENGTH_SHORT).show();
    }

这是我的DiffUtil类:

Here is my DiffUtil class:

class DiffCb extends DiffUtil.Callback {
    private final List<PostItems> oldItems;
    private final List<PostItems> newItems;

    public DiffCb(List<PostItems> oldItems, List<PostItems> newItems) {
        this.oldItems = oldItems;
        this.newItems = newItems;
    }

    @Override
    public int getOldListSize() {
        return oldItems.size();
    }

    @Override
    public int getNewListSize() {
        return newItems.size();

    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldItems.get(oldItemPosition).equals(newItems.get(newItemPosition));
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldItems.get(oldItemPosition).equals(newItems.get(newItemPosition));
    }
}

像这样更新recyclerView:

Updating recyclerView like that:

postList.addAll(response.body());
postAdapter.updateItems(homePostList);

当NestedScrollView或ScrollView中未包含我的recyclerView时,一切正常.

Everything work fine when my recyclerView is not contained in a NestedScrollView or ScrollView.

但是当我的recyclerView包含在NestedScrollView或ScrollView中时,更新recyclerView会继续阻塞主线程,就像禁用了DiffUtil一样.

But when my recyclerView is contained in a NestedScrollView or ScrollView, updating the recyclerView keep blocking the main thread as if the DiffUtil were disabled.

在更新NestedScrollView或ScrollView中包含的recyclerView时如何防止阻塞主线程?

How to prevent blocking the main thread when updating the recyclerView contained in a NestedScrollView or ScrollView ?

谢谢.

推荐答案

尝试不要每次都创建新适配器,而是更新适配器内的数据.另外,如果您使用 DiffUtils ,则应在 PostItems 类中覆盖 .equals .hashcode ,因此,DIffUtils 可以知道哪个对象是新对象,哪个对象已经存在.

Try to not create everytime new adapter, but instead update data inside adapter. Also if you use DiffUtils, you should override .equals and .hashcode in your PostItems class so DIffUtils can know which object is new and which object already exists.

在您的 PostItems 类的某个地方单击鼠标右键,然后选择 Generate ,然后选择 override equals and hashcode ,然后选择类中的唯一字段.

Click right mouse in somewhere your PostItems class and choose Generate, then choose override equals and hashcode, then choose unique field in class.

此外,您还应该在ViewHolder类中绑定视图
例如:

Also you should bind views in your ViewHolder class
For example:

       static class PostViewHolder extends RecyclerView.ViewHolder {
            TextView tv1;
            TextView tv2;
            PostViewHolder(@NonNull View itemView) {
                super(itemView);
                tv1 = itemView.findViewById(R.id.tv1);
                tv2 = itemView.findViewById(R.id.tv2);
            }
        }

然后在 .bindViewHolder 方法中,您可以像以下方式访问视图:

Then in .bindViewHolder method you access your view like:

    @Override
    public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
        PostItems post_items = postList.get(position);
        holder.tv1.setText(post_items.get_text_wall_post());
        //etc
    }

主要思想是不要每次都在 .bindViewHolder 方法中调用 .findViewById(),因为它会很慢地调用 RecyclerView

Main idea is to not call everytime .findViewById() in .bindViewHolder method, because it's slow enaugh for RecyclerView

这篇关于使用DiffUtil,如何在更新NestedScrollView中包含的recyclerView时防止阻塞主线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆