使用DiffUtil,如何在更新NestedScrollView中包含的recyclerView时防止阻塞主线程? [英] Using DiffUtil, How to prevent blocking the main thread when updating the recyclerView contained in a NestedScrollView?
问题描述
我正在尝试在后台线程中对我的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屋!