Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
DiffUtil makes RecyclerView more useful
A few days ago, when I wrote the partial refresh of RecyclerView, some of my friends mentioned DiffUtil in the comment area. To tell the truth, DiffUtil really has not been used in the project. I checked the information and found that DiffUtil helped us to do a lot of work to refresh.
What is DiffUtil
DiffUtil is a utility class derived from RecycleView-V7. Diff directly translates to difference and contrast, so this utility class mainly helps us compare two data sets to find the minimum change. So what does it have to do with RecyclerView, in fact we just give DiffUtil the old and the new data sets, and it will automatically compare the data for us, and refresh the adapter, without us having to judge whether it’s added or deleted, and so on, and the DiffUtil comparison will automatically do it for us, and that’s where it works really well, right
Generic adapters
Let’s start by writing a regular list in RecyclerView. It has the ability to refresh items and refresh items locally. The code is as follows:
MainActivity: main interface
public class MainActivity extends AppCompatActivity { private RecyclerView recyclerView; private List<PersonInfo> mDatas; private PersonAdapter personAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recyclerView); initData(); recyclerView.setLayoutManager(new LinearLayoutManager(this)); personAdapter = new PersonAdapter(this, mDatas); recyclerView.setAdapter(personAdapter); } private void initData() { mDatas = new ArrayList<>(); Mdatas.add (new PersonInfo(1, "name 1")); Mdatas.add (new PersonInfo(2, "name 2")); Mdatas.add (new PersonInfo(3, "name 3")); Mdatas.add (new PersonInfo(4, "name 4")); Mdatas.add (new PersonInfo(5, "name 5")); Mdatas.add (new PersonInfo(6, "name 6")); Mdatas.add (new PersonInfo(7, "name 7")); Mdatas.add (new PersonInfo(8, "name 8")); Mdatas.add (new PersonInfo(9, "name 9")); Mdatas.add (new PersonInfo(10, "name 10")); Mdatas.add (new PersonInfo(11, "name 11")); } public void ADD(View view) { int position = mDatas.size(); List<PersonInfo> tempData = new ArrayList<>(); Tempdata.add (new PersonInfo(12, "name 12")); Tempdata.add (new PersonInfo(13, "name 13")); Tempdata.add (new PersonInfo(14, "name 114")); mDatas.addAll(tempData); personAdapter.notifyItemRangeInserted(position, tempData.size()); } public void DELETE(View view) { mDatas.remove(1); personAdapter.notifyItemRemoved(1); } public void UPDATE(View View) {mdatas.get (1).setName(" name: I am updated "); personAdapter.notifyItemChanged(1); } public void UPDATE2(View View) {mdatas.get (1).setName(" name "); Bundle payload = new Bundle(); payload.putString("KEY_NAME", mDatas.get(1).getName()); personAdapter.notifyItemChanged(1, payload); }}Copy the code
PersonAdapter: adapter
public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.DiffVH> { private List<PersonInfo> mDatas; private LayoutInflater mInflater; public PersonAdapter(Context context, List<PersonInfo> mDatas) { this.mDatas = mDatas; mInflater = LayoutInflater.from(context); } public void setDatas(List<PersonInfo> mDatas) { this.mDatas = mDatas; } @Override public DiffVH onCreateViewHolder(ViewGroup parent, int viewType) { return new DiffVH(mInflater.inflate(R.layout.item_person, parent, false)); } @Override public void onBindViewHolder(final DiffVH holder, final int position) { PersonInfo personInfo = mDatas.get(position); holder.tv_index.setText(String.valueOf(personInfo.getIndex())); holder.tv_name.setText(String.valueOf(personInfo.getName())); } @Override public void onBindViewHolder(DiffVH holder, int position, List<Object> payloads) { if (payloads.isEmpty()) { onBindViewHolder(holder, position); } else { Bundle payload = (Bundle) payloads.get(0); PersonInfo bean = mDatas.get(position); for (String key : payload.keySet()) { switch (key) { case "KEY_INDEX": holder.tv_index.setText(String.valueOf(bean.getIndex())); break; case "KEY_NAME": holder.tv_name.setText(String.valueOf(bean.getName())); break; default: break; } } } } @Override public int getItemCount() { return mDatas ! = null ? mDatas.size() : 0; } class DiffVH extends RecyclerView.ViewHolder { TextView tv_index; TextView tv_name; public DiffVH(View view) { super(view); tv_index = view.findViewById(R.id.tv_index); tv_name = view.findViewById(R.id.tv_name); }}}Copy the code
PersonInfo: entity class
public class PersonInfo { private int index; private String name; public PersonInfo(int index, String name) { this.index = index; this.name = name; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public String getName() { return name; } public void setName(String name) { this.name = name; }}Copy the code
activity_main
<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="wrap_content" Android :layout_height="wrap_content" Android :text=" ADD" Android :onClick="ADD"/> <Button Android :layout_width="wrap_content" Android :layout_height="wrap_content" Android :text=" DELETE" Android :onClick="DELETE"/> <Button android:layout_width="wrap_content" Android :layout_height="wrap_content" Android :text=" modify" android:onClick="UPDATE"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" Android: text = "local update" android: onClick = "out" / > < / LinearLayout > <. Android support. V7. Widget. RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>Copy the code
item_person
<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" tools:context=".MainActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:background="@color/purple_200" android:orientation="horizontal" android:padding="5dp"> <TextView android:id="@+id/tv_index" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toEndOf="@+id/tv_index" /> </RelativeLayout> </LinearLayout>Copy the code
The introduction of DiffUtil
We create a DiffUtil class that replaces the refresh method with the DiffUtil method when it needs to be updated.
Use the new example, so that you can achieve the purpose of updating
public void ADD(View view) { List<PersonInfo> newData = new ArrayList<>(); newData.addAll(mDatas); Newdata.add (new PersonInfo(12, "name 12")); Newdata.add (new PersonInfo(13, "name 13")); Newdata.add (new PersonInfo(14, "name 114")); DiffUtil.calculateDiff(new DiffUtilCallBack(newData,mDatas), true).dispatchUpdatesTo(personAdapter); mDatas = newData; personAdapter.setDatas(mDatas); }Copy the code
DiffUtilCallBack
public class DiffUtilCallBack extends DiffUtil.Callback { private List<PersonInfo> newlist; private List<PersonInfo> oldlist; public DiffUtilCallBack(List<PersonInfo> newlist, List<PersonInfo> oldlist) { this.newlist = newlist; this.oldlist = oldlist; } @Override public int getOldListSize() { return oldlist.size(); } @Override public int getNewListSize() { return newlist.size(); } @override public Boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { So this is where we can do the logic to determine if it's the same item, Return newlist.get(newItemPosition).getIndex() == oldList.get (oldItemPosition).getIndex(); } @override public Boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { This method is called when the above method returns true, because even though the item is the same, Return newList.get (newItemPosition).getName().equals(oldList.get (oldItemPosition).getName()); return newList.get (newItemPosition).getName(). }}Copy the code
DiffUtil in the universal adapter
Cooperate RecyclerView, I’ve been using universal adapter (BaseRecyclerViewAdapterHelper), if you are accustomed to using universal adapter, in its 3.0 method introduced support for DiffUtil.
Go straight to the official documentation.
Let me direct