Antonio Leiva
Time: Sep 12, 2016
Original link: http://antonioleiva.com/recyclerview-diffutil-kotlin/
As you know, the "Support Library 24" includes a new, applicable, and convenient class: Diffutil, which allows you to get rid of the boredom and error of cell changes and updates.
If you don't know it yet, you can read Nicola Despotoski's good article about it. This article explains how easy it is to handle it.
In fact, the Java language introduced many templates, and I decided to study how it was implemented with Kotlin.
Example
I created a small app (which can be downloaded on github) as an example, and it selects items from a list of 10 items for the next recycerview.
Thus, from one iteration to the next, some are shown, some disappear, and sometimes the whole is updated.
If you know how Recyclerview works, you know how the adapter notifies those changes, which requires these three methods:
- Notifyitemchanged
- notifyiteminserted
- Notifyitemremoved
And the range changes they correspond to.
The Diffutil class will do all the calculations and invoke the required notify method.
Original Implementation method
For the first iteration, we get these items from the "provider," which allows the adapter to notify the change (which, if not the best code, can quickly understand why):
1 Private Fun Filladapter () {2 val olditems = adapter.items3 adapter.items = Provider.generate ()4 adapter.notifychanges (OldItems, Adapter.items)5 }
Simple: I save the previous project, generate a new project, say notifychanges to the adapter, and use the Diffutil method is this:
1Fun Notifychanges (Old:list<content>,New: list<content>) {2Val diff =Diffutil.calculatediff (Object:DiffUtil.Callback () {3 Override Fun Areitemsthesame (Olditemposition:int, Newitemposition:int): Boolean {4 returnOld[olditemposition].id = =New[Newitemposition].id5 }6 7 Override Fun Arecontentsthesame (Olditemposition:int, Newitemposition:int): Boolean {8 returnOld[olditemposition] = =New[Newitemposition]9 }Ten OneOverride Fun getoldlistsize () =old.size A -Override Fun getnewlistsize () =New. Size - }) the -Diff.dispatchupdatesto ( This) -}
Since most of the code is based on templates, this is annoying, but it's going to be back later.
Now, as you can see, I called notifychanges after setting up a new set of items. Then why don't we entrust those acts?
Make notifications easier with delegates
If we know that every time a group of items is notified, then only Delegates.observer is needed, then the code is great:
This activity is very simple:
1 Private Fun Filladapter () {2 adapter.items = provider.generate ()3 }
The observer looks very good:
1 class Contentadapter ():recyclerview.adapter<contentadapter.viewholder>() {23 var Items:list<content> by delegates.observable (Emptylist ()) {4 new -5 New)6 }7 ... 8 }
That's great! However, this can be even better.
Ability to boost adapters with extension functions
Most of Notitychanges's code is modeled. With data classes, we need to implement a method that determines whether two items are the same, even if their contents are different.
In this example, the identification method is the ID.
In this way, I create an extension function for this adapter that will do most of the hard work for us:
1Fun <T> recyclerview.adapter<*>.autonotify (old:list<t>,New: List<t>, compare: (T, T),Boolean) {2Val diff =Diffutil.calculatediff (Object:DiffUtil.Callback () {3 4 Override Fun Areitemsthesame (Olditemposition:int, Newitemposition:int): Boolean {5 returnCompare (Old[olditemposition],New[newitemposition])6 }7 8 Override Fun Arecontentsthesame (Olditemposition:int, Newitemposition:int): Boolean {9 returnOld[olditemposition] = =New[Newitemposition]Ten } One AOverride Fun getoldlistsize () =old.size - -Override Fun getnewlistsize () =New. Size the }) - -Diff.dispatchupdatesto ( This) -}
This function receives two sets of items, and another function. This final parameter will be used in areitemsthesame to determine whether the two groups of items are the same.
Now the call is like this:
1 var items:list<content> by Delegates.observable (Emptylist ()) {2 new 3 new) {o, n-o.id = = N.id}4 }
Combined use
I can understand that you really don't like the solution in front of you. And in certain cases, you don't want all adapters to use it.
However, there is a replacement method: interface.
Sadly, in some locations on the Kotlin preview, the interface cannot extend the class (I would very much like to be able to add it in the future). This allows you to enforce the class implementation of the interface type using the method of the extension class.
However, we can also get similar results by moving the extension function inside the interface:
1 Interface Autoupdatableadapter {23 new: List<t>, compare: (T, T), Boolean) {4 ... 5 }6 }
The adapter only needs to implement this interface:
1 class Contentadapter (): Recyclerview.adapter<contentadapter.viewholder>(), Autoupdatableadapter {2 .... 3 }
That's all the code, and the rest stays the same.
Conclusion
There are several ways to use DIFFUTLS to make code look better and simpler than Java.
If you need to try another solution, get from the code base and remove some special comments.
Kotlin Secret recipe for Android (II): Recyclerview and Diffutil