Copyright Notice:

This account published articles are from the public account, Chengxiang Moying (cxmyDev), chengxiang Moying all rights reserved.

Every week will be uniformly updated here, if you like, you can follow the public account to get the latest article.

Shall not be reproduced without permission.

One, foreword

DIffUtils is an updated utility class in support-V7:24:2.0. Because it has been updated for some time, it is not the latest update.

It is mainly for the use of RecyclerView, through the comparison of the difference between the new and the old two data sets, generate the minimum change from the old data to the new data, and then the changed data items, local refresh.

Next, I will give a detailed explanation of DiffUtil usage. I hope that this article will fully understand DiffUtil.

2. Why DiffUtil

RecyclerView has been described as the perfect replacement for ListView, GridView and other list controls since its release. It’s also pretty easy to use, with layout switches, built-in ViewHolder, local updates and update animations, etc.

Local updates, and can be easily set up to update animation, RecyclerView is a nice highlight. It provides a corresponding method for this:

  • adapter.notifyItemChange()
  • adapter.notifyItemInserted()
  • adapter.notifyItemRemoved()
  • adapter.notifyItemMoved();

The above methods are used to operate on a single item in a data set, and the corresponding notifyRangeXxx() method is provided to operate on changes in a continuous data set.

Although RecyclerView provides the method of local update, it seems very easy to use, but in fact, there is no use.

In real development, the most convenient approach is to mindlessly call notifyDataSetChanged() to update the Adapter data set.

Although notifyDataSetChanged() has some disadvantages:

  • Animation that does not trigger a partial update of RecyclerView.
  • Low performance, will refresh the whole RecyclerView visual area.

But there are scenarios where you have to refresh two sets of data frequently.

Scenario 1: Use a notifyDataSetChanged() method.

Scheme 2: Write a data set comparison method, and then calculate their difference, and finally call the corresponding method to update RecyclerView.

I’m so lazy, if I didn’t have to, I’d choose plan one. After all, and before the ListView, there is no worse.

Google apparently figured this out too, so DiffUtil was published.

3. Introduce DiffUtil

As mentioned earlier, DiffUtil is designed to address this pain point. It can be very convenient to compare between two data sets, and then calculate the change, RecyclerView.Adapter, can automatically call the corresponding method of Adapter according to the change.

Of course, DiffUtil can not only be used with RecyclerView, it can actually be used separately to compare two data sets, and then how to do it is customizable, so it is up to us to use it in different scenarios.

In the use of DiffUtil, there are several classes to focus on:

  • Diffutil. Callback: Specifically used to restrict the data set alignment rules.
  • DiffUtil.DiffResult: The difference result returned after comparing data sets.

1, DiffUtil. Callback

The main purpose of diffUtil. Callback is to define the comparison rules of subitems in two data sets. After all, developers face a variety of data structures, and since there is no universal way to compare content, the rules of comparison should be handed back to developers.

In Callback, there are really only four methods that need to be implemented:

  • getOldListSize(): The length of the old data set.
  • getNewListSize(): The length of the new data set
  • areItemsTheSame(): Checks whether it is the same Item.
  • areContentsTheSame(): This method is used to check whether the contents of the same Item are the same.

The first two are ways to get the length of the data set, which is nothing to say. But the latter two methods were created primarily to correspond to the case of multiple layouts, that is, multiple viewTypes and multiple Viewhodlers. You first need to use the areItemsTheSame() method to check whether the contents are from the same viewType (that is, the same ViewHolder), and then use the areContentsTheSame() method to check whether the contents are also equal.

The Callback also has a getChangePayload() method, which can record the View payLoad that needs to be updated in the ViewHolder if the ViewType is the same but the content is different.

AreItemsTheSame (), areContentsTheSame(), and getChangePayload() represent different levels of refresh.

AreItemsTheSame () is used to determine whether the ViewType of the current position is consistent. If the ViewType is inconsistent, it indicates that the current position has changed from the data to the UI structure. The areContentsTheSame() method is used to determine whether the content of the View is consistent. If the content is consistent, it means that it is the same data and no additional operations are required. However, in case of inconsistency, getChangePayload() is also called to mark where the difference is, and finally to mark where it needs to be updated, which is returned to DiffResult.

Of course, you can skip the getChangedPayload() method if the performance requirements are not that high.

2, DiffUtil DiffResult

The DiffUtil.DiffResult is actually the DiffUtil calculated through DiffUtil.Callback, the difference between two data sets. It can be used directly in RecyclerView. If necessary, you can compare these differences by implementing the ListUpdateCallback interface.

3. Use DiffUtil

With Callback and DiffResult introduced, DiffUtil is now a normal way to compare data sets.

In this process, it is really simple, just call two methods:

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(oldDatas, newDatas), true);
diffResult.dispatchUpdatesTo(mAdapter);Copy the code

The calculateDiff method is mainly used to calculate the difference between two data sets through a concrete Diffutils.callback implementation object to obtain diffUtil.DiffResult.

The other parameter of calculateDiff is used to mark whether Item movement needs to be detected.

DiffUtil uses Eugene Myers’s differential algorithm, which itself does not check for element movement. In other words, any movement of an element will be marked first as deletion and then as insert. If the movement of an element needs to be calculated, it is actually checked again after the comparison with the Eugene Myers algorithm. So, if the set itself is already sorted, you don’t need to check for movement.

DispatchUpdatesTo () is the result of this data set difference, through Adapter update to RecyclerView.

Actually dispatchUpdatesTo(Adapter), which also uses the ListUpdateCallback interface, gets the difference and then calls the corresponding method of the Adapter.

diff-dut

Four, the example

Now that that’s clear, let’s move on to examples.

The function is very simple, there are four data sets, using RecyclerView load, and then there is a button, for the rotation of switching data sets.

Implement DiffUtil.callback

For simplicity, RecyclerView uses a single ViewType and uses a TextView to hold a string for display.

So we start implementing Callback:

diff-callback

2. Switch data sets

Now that we have the DiffUtil.callback implementation in place, we need to handle the click event that switches the dataset.

diff-change

3, achieve the effect

The key code has been posted, in fact, very simple, the final run effect is as follows:

5. DiffUtil efficiency

Since DiffUtil is very useful and has a set of algorithms implemented internally, we also need to be concerned about its efficiency.

The DiffUtil efficiency problem on Nexus 5X M system is presented as an example in Google’s official documentation, and some reference data are given:

diff-duibi

It can be seen that, in fact, DiffUtil’s algorithm solves the efficiency problem very well. With computation-moving enabled, there were 200 changes out of 1000, and the average was only 13.54ms, basically in milliseconds.

Google officials also pointed out that if the comparison of large data sets, it is best to complete the calculation in the child thread, which is actually the situation of blocking the UI. So if you run into a situation where each refresh is stuck after using DiffUtil, consider whether the data set is too large and whether the calculation should be done in child threads.

Six, the concluding

DiffUtil has been introduced, if you find this article helpful. Now that you’ve seen it, give it a thumbs up before you go.

Qr code. JPG