I'm trying to udate my recyclerView in background Thread without any succes.
Updating the recyclerView still block the main thread.
Here my adapter:
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();
}
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));
}
}
Updating recyclerView like that:
postList.addAll(response.body());
postAdapter.updateItems(homePostList);
Everything work fine when my recyclerView is not contained in a NestedScrollView or ScrollView.
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.
How to prevent blocking the main thread when updating the recyclerView contained in a NestedScrollView or ScrollView ?
Thanks.
Try to not create everytime new adapter, but instead update data inside adapter. Also if you use
DiffUtils, you should override.equalsand.hashcodein yourPostItemsclass soDIffUtilscan know which object is new and which object already exists.Click right mouse in somewhere your
PostItemsclass and chooseGenerate, then chooseoverride equals and hashcode, then choose unique field in class.Also you should bind views in your ViewHolder class
For example:
Then in
.bindViewHoldermethod you access your view like:Main idea is to not call everytime
.findViewById()in.bindViewHoldermethod, because it's slow enaugh forRecyclerView