Since some people complain about the ListView performance I thought it might be interesting to fire some agents on it to look at it 😄
Current Optimizations (Already Implemented)
- DiffUtil for efficient adapter updates
- View recycling using template-based view types
- Stable IDs enabled via
setHasStableIds(true)
- Custom pre-caching during the first layout pass
- List animations disabled to reduce unnecessary UI work
RecyclerView.setItemViewCacheSize(0) with a custom workaround
Identified Performance Issues & Recommended Improvements
1. Linear Search in getAdapterIndex() / getRowByIndex()
Location: TiListView.java:462–528
Issue: Both methods perform a linear scan through all items while comparing the index field.
Impact: Each lookup is O(n). This occurs during scrolling and marker operations, increasing overhead on large lists.
Recommendation: Introduce an index lookup cache:
HashMap<Integer, ListItemProxy>
The map should be updated whenever list items change, enabling O(1) lookups.
2. Expensive DiffUtil Content Comparison
Location: TiRecyclerViewAdapter.java:193–198
Issue: areContentsTheSame() recomputes hashes every comparison:
final long oldHash = oldProperties.hashCode() ^ Arrays.hashCode(oldView.getChildren());
This requires creating new arrays and computing hashes repeatedly.
Impact: Significant overhead during dataset updates and increased GC pressure.
Recommendation: Cache computed hashes inside ListItemProxy (property hash + children hash) and reuse them.
3. Inefficient Search / Filter Implementation (implemented)
Location: TiListView.java:681–719
Issue: toLowerCase() is called on every item's searchableText during filtering.
Impact: Repeated string allocations and increased CPU usage.
Recommendation: Cache the lowercase representation (lowercaseSearchableText) when the property is assigned.
4. Inefficient LinkedList.contains() in Recyclable Map
Location: ListViewAdapter.java:139
Issue: Uses recyclableItems.contains(item) which is O(n) for LinkedList.
Recommendation: Replace with HashSet for O(1) checks or remove the check if the item was already removed earlier.
5. Selection Tracker Heavy Iteration
Location: TiListView.java:313–337
Issue: A new KrollDict is created for each selected item and the full selection is iterated on every change.
Impact: Excessive allocations and processing overhead.
Recommendation: Batch selection updates, reuse KrollDict objects, or defer processing.
6. Missing RecyclerView Optimizations
setHasFixedSize(true) Not Enabled by Default
Issue: Only enabled when explicitly configured.
Impact: RecyclerView cannot fully optimize layout calculations when item sizes are constant.
Recommendation: Enable automatically when list dimensions are known.
Missing RecycledViewPool Optimization
Issue: No custom configuration for RecyclerView.RecycledViewPool.
Recommendation: Preconfigure the pool with expected view type counts to reduce view inflation and improve recycling.
7. View Binding Inefficiencies
Location: ListViewHolder.java
Full Reset on Every Bind
Issue: reset() removes all views and re-adds them even when the template is unchanged.
Impact: Unnecessary view operations and layout work.
Recommendation: Skip reset() when the recycled view uses the same template.
Repeated Theme Attribute Resolution
Location: ListViewHolder.java:370–394
Issue: Theme attributes are resolved during every bind operation.
Impact: Repeated theme lookups and avoidable overhead.
Recommendation: Cache resolved theme attributes and reuse them during view binding.
Summary
Key improvements should focus on:
- Eliminating O(n) lookups
- Reducing object allocations
- Avoiding repeated hash/string calculations
- Improving RecyclerView recycling behavior
These changes should significantly improve scroll performance, update efficiency, and memory usage, especially for large datasets.
I'll do some tests and see if some of them work and are easy to test and verify.
Platforms
Android
Since some people complain about the ListView performance I thought it might be interesting to fire some agents on it to look at it 😄
Current Optimizations (Already Implemented)
setHasStableIds(true)RecyclerView.setItemViewCacheSize(0)with a custom workaroundIdentified Performance Issues & Recommended Improvements
1. Linear Search in
getAdapterIndex()/getRowByIndex()Location:
TiListView.java:462–528Issue: Both methods perform a linear scan through all items while comparing the
indexfield.Impact: Each lookup is O(n). This occurs during scrolling and marker operations, increasing overhead on large lists.
Recommendation: Introduce an index lookup cache:
The map should be updated whenever list items change, enabling O(1) lookups.
2. Expensive DiffUtil Content Comparison
Location:
TiRecyclerViewAdapter.java:193–198Issue:
areContentsTheSame()recomputes hashes every comparison:This requires creating new arrays and computing hashes repeatedly.
Impact: Significant overhead during dataset updates and increased GC pressure.
Recommendation: Cache computed hashes inside
ListItemProxy(property hash + children hash) and reuse them.3. Inefficient Search / Filter Implementation(implemented)Location:
TiListView.java:681–719Issue:
toLowerCase()is called on every item'ssearchableTextduring filtering.Impact: Repeated string allocations and increased CPU usage.
Recommendation: Cache the lowercase representation (
lowercaseSearchableText) when the property is assigned.4. Inefficient
LinkedList.contains()in Recyclable MapLocation:
ListViewAdapter.java:139Issue: Uses
recyclableItems.contains(item)which is O(n) forLinkedList.Recommendation: Replace with HashSet for O(1) checks or remove the check if the item was already removed earlier.
5. Selection Tracker Heavy Iteration
Location:
TiListView.java:313–337Issue: A new
KrollDictis created for each selected item and the full selection is iterated on every change.Impact: Excessive allocations and processing overhead.
Recommendation: Batch selection updates, reuse
KrollDictobjects, or defer processing.6. Missing RecyclerView Optimizations
setHasFixedSize(true)Not Enabled by DefaultIssue: Only enabled when explicitly configured.
Impact: RecyclerView cannot fully optimize layout calculations when item sizes are constant.
Recommendation: Enable automatically when list dimensions are known.
Missing
RecycledViewPoolOptimizationIssue: No custom configuration for
RecyclerView.RecycledViewPool.Recommendation: Preconfigure the pool with expected view type counts to reduce view inflation and improve recycling.
7. View Binding Inefficiencies
Location:
ListViewHolder.javaFull Reset on Every Bind
Issue:
reset()removes all views and re-adds them even when the template is unchanged.Impact: Unnecessary view operations and layout work.
Recommendation: Skip
reset()when the recycled view uses the same template.Repeated Theme Attribute Resolution
Location:
ListViewHolder.java:370–394Issue: Theme attributes are resolved during every bind operation.
Impact: Repeated theme lookups and avoidable overhead.
Recommendation: Cache resolved theme attributes and reuse them during view binding.
Summary
Key improvements should focus on:
These changes should significantly improve scroll performance, update efficiency, and memory usage, especially for large datasets.
I'll do some tests and see if some of them work and are easy to test and verify.
Platforms
Android