The problem
Picker's "add" method is very slow, when creating picker with 30 rows on tablet with Tegra2 processor, picker "add" method takes about 1.5 seconds to execute.
This greatly impacts Titanium's performance when there are more pickers with more that just a few options.
Test case
(function() {
var win = Ti.UI.createWindow({
backgroundColor: '#000'
});
var data = [];
var start = new Date();
for (var i = 0; i < 30; ++i) {
data[i] = Ti.UI.createPickerRow({ title: 'Row ' + i });
}
Ti.API.info('Rows: ' + (new Date() - start));
var picker = Ti.UI.createPicker();
start = new Date();
picker.add(data);
Ti.API.info('Finished: ' + (new Date() - start));
win.add(picker);
win.open();
})();
30 rows is really not big number, especially on powerful hardware. 1.5 seconds is a way too much. JS execution time (creation of array of picker's rows) is 14ms. Execution of "add" method should be similar to that value.
I have more info regarding this issue. If seems that slowdown exists only on startup. Here is updated test case:
When app starts, execution time is 1.5s (and that number is greater with bigger number of pickers), but performance is satisfying when other windows are created (and that can be seen if window is clicked and new picker is generated).
The original test case does not count the time correctly. When an app starts, a new activity is launched. After the activity is launched, it needs to go through three states - onCreate(), onStart() and onResume() before it is running. This process takes time. Therefore, the test code below is more accurate to count the time that the method picker.add() takes. It takes about 10ms.
But if I change picker code with table view code result is: 08-16 16:27:12.911: I/TiAPI(32075): Rows: 21 08-16 16:27:12.941: I/TiAPI(32075): Finished: 26 08-16 16:27:13.181: I/TiAPI(32075): OPEN: 271 Compare that with picker results: 08-16 16:14:46.871: I/TiAPI(31843): Rows: 20 08-16 16:14:48.361: I/TiAPI(31843): Finished: 1479 08-16 16:14:48.561: I/TiAPI(31843): OPEN: 1689 That's huge difference and I doubt that is normal (note that there is identical number of rows). After window in opened, there is no performance drop. This only happens when app lunches for the first time. Here is my code (table view part is commented):
picker.add() method needs to be done in the UI thread. The method sends a message to the message queue and UI thread will execute it as it comes out of the message queue. Therefore, if there are some other messages before this one, it will delay the execution of this method. I used the Android [Debug](http://developer.android.com/reference/android/os/Debug.html) class to generate the [traceview](http://developer.android.com/tools/debugging/debugging-tracing.html). When the app launches for the first time, picker.add() method takes 64.269ms in total and it spends 60.147ms in sending and handling messages, which means it only takes 4.122ms to handle the "add" action. When the app is already launched(eg. the window is already opened), picker.add() method takes 19.317ms in total and it spends 16.358ms in sending and handling messages, which means it takes 2.959ms to handle the "add" action. Considering the possible fluctuations, those numbers tell us the picker.add() method is not slow. It's just because when the app launches for the first time, there are a lot of messages / actions waiting to be taken care of in the UI thread which delay the method.
OK, thanks. I don't understand Titanium internals so I cannot comment is that normal or not. But as Titanium developer I think it's not normal that app loads slowly because of picker with 30 rows. It's not logical that TableView loads a lot faster with same number of rows. Here is example with 5 picker with 30 rows.
It takes 8 seconds to load application (same app with TableViews loads in 0.5 seconds)! IMO, that cannot be considered as normal or acceptable. Native app would load instantly.
I agree that it should not take 8 seconds in this scenario. We need to investigate this issue further.
Since I can't seem to find the vote button I'll comment that I'm also seeing this. We have two pickers with ~130 rows and they each take 9-10 seconds each the first time the app loads up. Subsequently they take 200-300ms each. IOS is not affected.
Escalating it for Homes.com.
Tested it on Master build 3.1.0.v20121019134913 and 3.X CI build 3.0.0.v20121019103112 with Android 3.1, 4.0 and 4.1. Same delay ( ~9secs ) is observed.
Pull request https://github.com/appcelerator/titanium_mobile/pull/3351
Notes on testing this fix for engineering and QE: (1) Ivan's example above consistently takes 8+ seconds to start on my Samsung Galaxy SII. After that the refresh of the picker is fairly quick (i.e. without restarting the app). So you'll need to make sure that the app is not running if you want to see the bug here. If app is already started, go to "Settings", then "Applications", select your test app and then click on "Force Stop", and then start the app. (2) With the change the app takes approx. 0.4 to 0.5 seconds to start, which is in line with the start time for the TableView example.
Re-opening pending pull request for 3_0_X branch
Pull request https://github.com/appcelerator/titanium_mobile/pull/3361 for 3_0_X branch
Tested with 3.0.0.v20121204144658 on Droid 1 2.2.3