RecyclerView blocking ui thread during updates

yusufonderd picture yusufonderd · Apr 25, 2017 · Viewed 8.3k times · Source

There are more than 200 items in my list. RecyclerView is updated regularly (Every 10 seconds) . RecyclerView blocking ui thread for few seconds during updates. I'm using notifyDataSetChanged method for refresh recyclerview. Is there another way to prevent freezing ? By the way I don't want use pagination.

This method run every 10 seconds :

public void refreshAssetList(List<Asset> newAssetList){
     recyclerViewAdapter.setAssetList(newAssetList);
     recyclerViewAdapter.notifyDataSetChanged();
}

RecyclerViewAdapter class :

public class AssetListRecyclerViewAdapter extends RecyclerView.Adapter<AssetListRecyclerViewAdapter.BaseViewHolder> {

    private List<Asset> assetList;
    Context context;

    public AssetListRecyclerViewAdapter(List<Asset> assetList, Context context) {
        this.assetList = assetList;
        this.context = context;
    }

    public void setAssetList(List<Asset> assetList) {
        this.assetList = assetList;
    }

    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_asset, null);
            return new DetailViewHolder(itemLayoutView);
    }

    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        Asset asset = assetList.get(position);
        Last last = asset.getLast();
        if (holder.getItemViewType() == TYPE_DETAIL) {
            DetailViewHolder mHolder = (DetailViewHolder) holder;
            mHolder.dateTextView.setText(last.getDate());
            mHolder.brandTextView.setText(asset.getMc());
        }
    }

     class DetailViewHolder extends BaseViewHolder {

        @Bind(R.id.brandTextV)
        TextView brandTextView;
        @Bind(R.id.dateTextV)
        TextView dateTextView;

         DetailViewHolder(View itemLayoutView) {
            super(itemLayoutView);
            ButterKnife.bind(this, itemLayoutView);
        }
    }

}

Answer

Haris Qureshi picture Haris Qureshi · Apr 25, 2017

You do not need to call notifyDataSetChanged, it's an expensive operation your whole RecyclerView will completely redraw, rebind etc.

As the doc says:

This event does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. LayoutManagers will be forced to fully rebind and relayout all visible views.

All you need to do is loop through every position and if needed update desired item otherwise do nothing or skip.

What you should do:

As you are updating your whole view first you need to compare your (visible) adapter's List<Asset> with new List<Asset> and retrieve only those items which you need to be update, once you have the list loop through updated list and update your adapter's view by using viewAdapter.notifyItemChanged(position).