Thursday, 13 July 2017

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:
Test 1
Test 2
Test 3
Test 4
Test 5
Test 6
Test 7
Test 8
Test 9
Test 10
Test 11
Test 12
The second page would then render:

Test 13
Test 14
Test 1
Test 15
Test 16
Test 4
Test 17
Test 18
Test 19
Test 20
Test 6
At 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.

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:
Test 1
Test 2
Test 3
Test 4
Test 5
Test 6
Test 7
Test 8
Test 9
Test 10
Test 11
Test 12
The second page:

Test 13
Test 14
Test 15
Test 16
Test 17
Test 18
Test 19
Test 20
Test 21
Test 22
Test 23
Test 24
Hurrah!

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. 

No comments:

Post a Comment