Fixing a Quirky "Xamarin.Forms ListView Bug" That Led Me Back to Basics And How Most Bugs Are Written By Users!
For the last two evenings I've been chasing what seemed a random bug. The crux of it came down to scrolling large lists within a ListView, 1000's of items, which were grouped, would muddle up the items and often duplicate an item a couple of times.
An example output:
First page of results:
Next I considered the code that grouped the items, again unit tests all good, toothcomb said still good.
So I sat pondering. Was there something similar about all of the duplicated items. There was, they were all items that didn't then link to a separate page.
I then suspected had I done a rookie mistake thats often easy to miss until you hit larger datasets. Had I overriden GetHashCode and done so poorly.... Let's write some tests to prove it...
So I hadn't modified the Equals and GetHashCode for a long time, I love how CodeLens helps with this. But I had added more properties to the object :(
An age ago I had added Section Id to the object but I hadn't added it to the Equals and GetHashCode as it was added to the base class and I just passed it through.
So time to implement Equals and GetHashCode properly and for good measure IEquatable<T> . I've always found a good way to implement these is either let Resharper help you or use the great examples on a popular StackOverflow post. Jon Skeet's example is great but Rick Love's is also quite elegant.
The results...
And then within the app itself....
An example output:
First page of results:
Test 1The second page would then render:
Test 2
Test 3
Test 4
Test 5
Test 6
Test 7
Test 8
Test 9
Test 10
Test 11
Test 12
Test 13At first glance this looked like a random error. I considered that maybe my list parsing code (the app takes HTML and makes in easier to use) but my unit tests checked out. So I went over these again with a toothcomb. All checked out.
Test 14
Test 1
Test 15
Test 16
Test 4
Test 17
Test 18
Test 19
Test 20
Test 6
Next I considered the code that grouped the items, again unit tests all good, toothcomb said still good.
So I sat pondering. Was there something similar about all of the duplicated items. There was, they were all items that didn't then link to a separate page.
I then suspected had I done a rookie mistake thats often easy to miss until you hit larger datasets. Had I overriden GetHashCode and done so poorly.... Let's write some tests to prove it...
FAIL |
So I hadn't modified the Equals and GetHashCode for a long time, I love how CodeLens helps with this. But I had added more properties to the object :(
Code Smells... |
The Change |
An age ago I had added Section Id to the object but I hadn't added it to the Equals and GetHashCode as it was added to the base class and I just passed it through.
So time to implement Equals and GetHashCode properly and for good measure IEquatable<T> . I've always found a good way to implement these is either let Resharper help you or use the great examples on a popular StackOverflow post. Jon Skeet's example is great but Rick Love's is also quite elegant.
The results...
BOOM! |
And then within the app itself....
First page of results:
So why would this issue cause the rendering issue? I suspected that the way the recycling listview works is by using HashSet's once an ItemsSource reached a certain size or as part of it's internals. I had a good poke at the Xamarin.Forms source code all on GitHub and I suspect its to do with the ListProxy but the why isn't super important, the issue is fixed and the issue is relatively easy to spot.
So this was a real reminder how we can't forget about basics and hopefuly offers an insight in how to spot the associated issue.
Test 1The second page:
Test 2
Test 3
Test 4
Test 5
Test 6
Test 7
Test 8
Test 9
Test 10
Test 11
Test 12
Test 13Hurrah!
Test 14
Test 15
Test 16
Test 17
Test 18
Test 19
Test 20
Test 21
Test 22
Test 23
Test 24
So why would this issue cause the rendering issue? I suspected that the way the recycling listview works is by using HashSet's once an ItemsSource reached a certain size or as part of it's internals. I had a good poke at the Xamarin.Forms source code all on GitHub and I suspect its to do with the ListProxy but the why isn't super important, the issue is fixed and the issue is relatively easy to spot.
So this was a real reminder how we can't forget about basics and hopefuly offers an insight in how to spot the associated issue.
Comments
Post a Comment