Problem:
Populating a table view with complex rows makes the entire Android UI very unresponsive until the rows are all loaded making the app unusable
Tests
1. *Test 1* One tab will load the first 10 rows in an array and populate the table view. After that, the nex 400+ rows will load on the table one by one. At this point the device is almost locked and nothing can be done.
2. *Test 2* On this other tab, I download the JSON, create an array of rows, and after, populate the table view with the array.
Test 2 would work, but populating the table view with so many rows, it takes too long.
To reproduce:
1. Run the app. On tab1 hit the menu button and click on "Start Downloading" A loading indicator will appear and disappear after the download is completed. Then, the first 10 rows will appear and the next 400+ rows will start populating the table view. At this point the UI is almost locked up, everything is very slow.
2. Click on tab2 and hit the menu button and then on "Start Downloading" This one takes longer for the rows to appear, so test1 would be a better solution from a user stand-point.
The Code:
var tabGroup = Ti.UI.createTabGroup();
var win1 = Ti.UI.createWindow({
url:'win1.js'
});
var win2 = Ti.UI.createWindow({
url:'win2.js'
});
var tab1 = Ti.UI.createTab({
window:win1,
title:'Test 1'
});
var tab2 = Ti.UI.createTab({
window:win2,
title:'test 2'
});
tabGroup.addTab(tab1);
tabGroup.addTab(tab2);
tabGroup.open();
var win = Ti.UI.currentWindow;
win.backgroundColor='#fff';
var xhr = Ti.Network.createHTTPClient();
var tableView = Ti.UI.createTableView();
win.add(tableView);
var act = Ti.UI.createActivityIndicator({
message:'Downloading...'
});
function customRow(a){
a = a || {};
a.image = a.pic_square || '';
a.name = a.name || '';
a.id = a.uid || '';
var img = Ti.UI.createImageView({
image:a.image,
width:80,
left:10
});
var label = Ti.UI.createLabel({
left:100,
top:10,
bottom:10,
text:a.name
});
var row = Ti.UI.createTableViewRow({
rowId:a.id,
className:'custom_row'
});
row.add(img);
row.add(label);
return row;
}
xhr.onload = function(){
act.hide();
Ti.API.info('loading......');
var startTime = new Date().getTime();
var json = JSON.parse(this.responseText);
var initData = [];
for(var i = 0; i < 9;i++){
initData.push(
customRow(json[i])
);
}
tableView.data = initData;
// this is how long it too for the rows to be displayed
alert(new Date().getTime()-startTime);
for(var i = 9; i < json.length;i++){
tableView.appendRow(customRow(json[i]));
}
}
xhr.open('GET', 'http://jwtdigital.co.il/tools/tmp/json_data.php');
win.activity.onCreateOptionsMenu = function(e) {
var menu = e.menu;
var m1 = menu.add({ title : 'Start Download' });
m1.addEventListener('click', function(e) {
act.show();
xhr.send();
});
};
var win = Ti.UI.currentWindow;
win.backgroundColor='#fff';
var xhr = Ti.Network.createHTTPClient();
var tableView = Ti.UI.createTableView();
win.add(tableView);
var act = Ti.UI.createActivityIndicator({
message:'Downloading...'
});
function customRow(a){
a = a || {};
a.image = a.pic_square || '';
a.name = a.name || '';
a.id = a.uid || '';
var img = Ti.UI.createImageView({
image:a.image,
width:80,
left:10
});
var label = Ti.UI.createLabel({
left:100,
top:10,
bottom:10,
text:a.name
});
var row = Ti.UI.createTableViewRow({
rowId:a.id
});
row.add(img);
row.add(label);
return row;
}
xhr.onload = function(){
act.hide();
Ti.API.info('loading......');
var startTime = new Date().getTime();
var json = JSON.parse(this.responseText);
var initData = [];
for(var i = 0; i < json.length;i++){
initData.push(
customRow(json[i])
);
Ti.API.info(i);
}
tableView.data = initData;
// this is how long it too for the rows to be displayed
alert(new Date().getTime()-startTime);
}
xhr.open('GET', 'http://jwtdigital.co.il/tools/tmp/json_data.php');
win.activity.onCreateOptionsMenu = function(e) {
var menu = e.menu;
var m1 = menu.add({ title : 'Start Download' });
m1.addEventListener('click', function(e) {
act.show();
xhr.send();
});
};
Associated Helpdesk Ticket:
AGM-15481-948
Attached is a zip with the files.
Triage and try to have appendRow accept an array of items to see if the performance boost is significant.
In the future, there will be a new list view style implementation that will make dealing with these issues much easier. It is also planned that 1.8 will include worker threads which will allow further options in increasing performance for operations like this. In the mean time, I have attached a working example that shows a way of handling the loading in the background for the most part without affecting the UI responsiveness. The tab 2 example, shows the new approach.
work around for loading table data in the background
create new tickets to support appendRow being allowed to take an array of rows rather than just a single row / row data Android: 4916 iOS: 4917
Attaching missing builder.js file required by test in the previously attached app.zip
To run test, follow the above instructions but first grab the attached builder.js and drop it in the resources directory along with app.js
Tested with 1.8.0.v20110819142548 Motorola Xoom 3.2 Nexus One 2.2.2