▲ Click the “CocoaChina” above to follow and learn iOS development for free
Original link: http://www.cnblogs.com/Fndroid/p/5789470.html
Google recently updated the Support Library to version 24.2.0, and DiffUtil is a utility class added in this version. DiffUtil is a tool for finding changes in collections, used in conjunction with RecyclerView.
As per tradition, here is a preview:
As you can see, when we click the button, the collection displayed by this RecyclerView changes; some elements are added (8. Jason), some are moved (3. Rose), and some are modified (2. Fndroid). RecyclerView refreshes the animations for each item in different ways:
-
notifyItemInserted
-
notifyItemChanged
-
notifyItemMoved
-
notifyItemRemoved
For refreshing a range of consecutive items, you can call:
-
notifyItemRangeChanged
-
notifyItemRangeInserted
-
notifyItemRangeRemoved
However, when the collection changes, you can only call notifyDataSetChanged to refresh the entire interface, which does not allow for adding animations for each changed element based on the changes in the collection. This is where DiffUtil comes in to solve the problem.
DiffUtil’s role is to identify each item’s changes in the collection and apply corresponding refreshes for each change.
This DiffUtil uses Eugene Myers’ differencing algorithm, which cannot detect item movements; movements are considered as first deleting and then adding. However, DiffUtil performs a second movement check after the algorithm’s results. Assuming that the algorithm’s time complexity without movement detection is O(N + D²), detecting movements results in a complexity of O(N²). Therefore, if the collection is already sorted, you can skip movement detection to improve efficiency.
Now let’s look at how to use this tool.
First, for each item, the data is a Student object:
1 class Student {2 private String name;3 private int num;45 public Student(String name, int num) {6 this.name = name;7 this.num = num;8 }910 public String getName() {11 return name;12 }1314 public void setName(String name) {15 this.name = name;16 }1718 public int getNum() {19 return num;20 }2122 public void setNum(int num) {23 this.num = num;24 }25 }
Next, we define the layout (omitted) and the adapter:
1 class MyAdapter extends RecyclerView.Adapter {2 private ArrayList<Student> data;34 ArrayList<Student> getData() {5 return data;6 }78 void setData(ArrayList<Student> data) {9 this.data = new ArrayList<>(data);10 }1112 @Override13 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {14 View itemView = LayoutInflater.from(RecyclerViewActivity.this).inflate(R.layout.itemview, null);15 return new MyViewHolder(itemView);16 }1718 @Override19 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {20 MyViewHolder myViewHolder = (MyViewHolder) holder;21 Student student = data.get(position);22 myViewHolder.tv.setText(student.getNum() + “.” + student.getName());23 }2425 @Override26 public int getItemCount() {27 return data.size();28 }2930 class MyViewHolder extends RecyclerView.ViewHolder {31 TextView tv;3233 MyViewHolder(View itemView) {34 super(itemView);35 tv = (TextView) itemView.findViewById(R.id.item_tv);36 }37 }38 }
Initialize the data collection:
1 private void initData() {2 students = new ArrayList<>();3 Student s1 = new Student(“John”, 1);4 Student s2 = new Student(“Curry”, 2);5 Student s3 = new Student(“Rose”, 3);6 Student s4 = new Student(“Dante”, 4);7 Student s5 = new Student(“Lunar”, 5);8 students.add(s1);9 students.add(s2);10 students.add(s3);11 students.add(s4);12 students.add(s5);13 }
Then instantiate the Adapter and set it to the RecyclerView:
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_recycler_view);initData();recyclerView = (RecyclerView) findViewById(R.id.rv);recyclerView.setLayoutManager(new LinearLayoutManager(this));adapter = new MyAdapter();adapter.setData(students);recyclerView.setAdapter(adapter);}
These contents are not the focus of this article, but one thing to note is the definition of the Adapter:
1 class MyAdapter extends RecyclerView.Adapter {2 private ArrayList<Student> data;34 ArrayList<Student> getData() {5 return data;6 }78 void setData(ArrayList<Student> data) {9 this.data = new ArrayList<>(data);10 }1112 // Omitted some code13 ……14 }
The setData method does not directly save the reference of the ArrayList but creates a new ArrayList instead; remember this, as it will be explained later.
Using DiffUtil:
When the mouse is pressed, modify the contents of the ArrayList:
1 public void change(View view) {2 students.set(1, new Student(“Fndroid”, 2));3 students.add(new Student(“Jason”, 8));4 Student s2 = students.get(2);5 students.remove(2);6 students.add(s2);78 ArrayList<Student> old_students = adapter.getData();9 DiffUtil.DiffResult result = DiffUtil.calculateDiff(new MyCallback(old_students, students), true);10 adapter.setData(students);11 result.dispatchUpdatesTo(adapter);12 }
Lines 2-6 modify the collection, and line 8 retrieves the old data from the adapter.
Focus on line 9, which calls DiffUtil.calculateDiff to calculate the differences between the collections. Here, you need to pass an implementation of the Callback interface (to specify the calculation rules) and pass the new and old data to this interface implementation, along with a boolean parameter that specifies whether to check for movements. If not checked, if any items are moved, they will be considered as first removed and then inserted. Here it is set to true, so the animation showing the movement is displayed.
Line 10 reassigns the new data to the adapter.
Line 11 calls the dispatchUpdatesTo method of the DiffResult object obtained from line 9 to notify the RecyclerView to refresh the changed items.
Returning to the setData method, we need to distinguish between the two collections here. If the setData method saves the reference directly, then the modifications on lines 2-6 will directly modify the collection in the adapter (Java knowledge).
If the setting does not check for item movements, the effect is as follows:
Next, let’s see how to define the implementation class of the Callback interface:
1 private class MyCallback extends DiffUtil.Callback {2 private ArrayList<Student> old_students, new_students;34 MyCallback(ArrayList<Student> data, ArrayList<Student> students) {5 this.old_students = data;6 this.new_students = students;7 }89 @Override10 public int getOldListSize() {11 return old_students.size();12 }1314 @Override15 public int getNewListSize() {16 return new_students.size();17 }1819 // Determine if the item exists20 @Override21 public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {22 return old_students.get(oldItemPosition).getNum() == new_students.get(newItemPosition).getNum();23 }2425 // If the item exists, this method is called to check if the item content is consistent26 @Override27 public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {28 return old_students.get(oldItemPosition).getName().equals(new_students.get(newItemPosition).getName());29 }30 }
Here, we determine whether the item is the same based on the student number and whether the item has been modified based on the name.
Note: If a large amount of data is loaded into the RecyclerView, the algorithm may not complete immediately, and you should be aware of ANR issues. You can start a separate thread for the calculation.
END
▼
Recommended by the editor:[Juejin] is a high-quality technical community where you can learn about everything from Swift to React Native, performance optimization to motion source code, ensuring you don’t miss out on any technical insights in iOS development. Long press the QR code to recognize or search for “Juejin” in major application markets to grasp all technical insights.
WeChat ID: CocoaChinabbs
▲ Long press the QR code to “recognize” and follow to learn iOS development for free
Monthly salary of 100,000, becoming a CEO, marrying a beautiful woman, and reaching the pinnacle of life is not a dream
——–—————–————-
Business cooperation QQ: 2408167315
Submission email: [email protected]