Titanium SDK List Performance: Choosing Between ListView and TableView
Learn why Ti.UI.ListView is the preferred choice for large datasets in Titanium SDK 8+, and how to implement declarative templates to avoid scroll jank and memory leaks.
02 Jul 2026, 13:08 UTC

When rendering lists in Titanium SDK, using Ti.UI.TableView for large datasets creates visible "jank" (stuttering) and escalating memory consumption. This happens because TableView creates a native view for every single row upfront. For applications targeting Titanium SDK 8+ on iOS and Android, the practical decision for lists exceeding 100 rows is to use Ti.UI.ListView with declarative item templates to leverage native cell recycling.
Decision Constraints and Requirements
Choose Ti.UI.ListView when the following constraints apply:
- The dataset is large (100+ items) or dynamic in size.
- The UI thread must remain responsive during fast scrolling.
- Memory growth must be capped regardless of list length.
- UI templates must be maintainable and reusable across iOS and Android.
Assumptions: This guide assumes Titanium SDK 8 or later using either Alloy or classic JavaScript. Note that template properties and separator behaviors vary by SDK version and platform; always verify against your specific SDK release notes.
Comparison of List Components
| Option | Rendering Model | Data Binding | Scroll Performance | Memory Usage | Complexity |
|---|---|---|---|---|---|
| TableView | Imperative (createRow) | Manual | Moderate (drops >200 rows) | High per row | Low |
| ListView | Recycled via templates | Sections/Items array | High (Native recycling) | Low/Stable | Medium |
| CollectionView | Grid/Recycled templates | Items array | High | Low/Stable | Medium-High |
Engineering Trade-offs
Ti.UI.ListView provides native cell recycling—where the system reuses a small number of views as the user scrolls—resulting in smoother performance. The trade-off is a loss of imperative flexibility; you cannot easily inject arbitrary view hierarchies into a specific row on the fly as you can with TableView.
ListView templates are defined as XML or JSON schemas. While this requires more upfront architectural planning than the "create-and-add" approach of TableView, it significantly improves long-term maintainability and ensures a consistent look across platforms.
Implementation and Validation
Alloy Implementation
Define the list and its template in the Alloy XML file. The bindId attribute maps the template element to a key in the data object.
<Alloy>
<ListView id="list" defaultItemTemplate="item" separatorColor="#eee">
</ListView>
<ListItemTemplate name="item">
<View layout="vertical">
<Label bindId="title" fontSize="16"></Label>
<Label bindId="subtitle" fontSize="12"></Label>
</View>
</ListItemTemplate>
</Alloy>
Bind the data in the controller. Use a structured array of objects where keys match the bindId.
var items = [];
for (var i = 0; i < 1000; i++) {
items.push({ title: 'Item ' + i, subtitle: 'Subtitle ' + i });
}
$.list.sections = [{
headerTitle: 'Main',
items: items
}];
Classic JavaScript Implementation
In non-Alloy projects, define the template object manually during the createListView call.
var templates = {
item: {
properties: { height: 60 },
childTemplates: [
{ type: 'Ti.UI.Label', bindId: 'title', properties: { left: 10, top: 5 } },
{ type: 'Ti.UI.Label', bindId: 'subtitle', properties: { left: 10, top: 25 } }
]
}
};
var listView = Ti.UI.createListView({
templates: templates,
defaultItemTemplate: 'item'
});
var data = [];
for (var i = 0; i < 1000; i++) {
data.push({ title: 'Item ' + i, subtitle: 'Subtitle ' + i });
}
listView.setData(data);
Operational Risks and Limitations
- Data Updates: Avoid rebuilding the entire list. Use
setDataor transactional updates to prevent full-reload jank. - Complex UI: ListView does not support arbitrary per-row view hierarchies. Highly complex interactive rows may require custom native modules.
- Platform Parity: Selection and separator behavior differs between Android and iOS. Test both platforms to ensure visual consistency.
Verification Steps
To validate the performance gain, follow these steps:
- FPS Profiling: Create a minimal app rendering 1,000 items using both
TableViewandListView. Use device developer tools (Xcode Instruments or Android Studio Profiler) to measure frame drops during rapid scrolling. - Memory Leak Check: Run a memory profiler while scrolling.
ListViewshould show a stable memory plateau, whereasTableViewwill show linear growth as more rows are instantiated. - SDK Validation: Cross-reference your template property names with the release notes of your specific Titanium SDK version to ensure compatibility.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.