Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-10363] Android: Picker "add" method is dead slow

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2012-10-30T21:35:44.000+0000
Affected Version/sRelease 2.1.0
Fix Version/sRelease 3.0.0, Release 3.1.0, 2012 Sprint 22 API, 2012 Sprint 22
ComponentsAndroid
Labels3.0.0beta2, api
ReporterIvan Skugor
AssigneeKarl Rowley
Created2012-07-11T03:07:05.000+0000
Updated2012-12-05T18:46:06.000+0000

Description

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.

Comments

  1. Ivan Skugor 2012-07-25

    I have more info regarding this issue. If seems that slowdown exists only on startup. Here is updated test case:
       var j = 0;
       
       
       function create() {
           
          var win = Ti.UI.createWindow({
               backgroundColor: '#000',
       		navBarHidden: true
          });
           
          var data = [];
           
          var start = new Date();
       
       	Ti.API.info(j);
           
          for (var i = j; i < (j + 30); ++i) {
               data.push(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);
       
       	j = j + 30;
       
       	win.addEventListener('open', function() {
       		Ti.API.info('OPEN: ' + (new Date() - start));
       	});
       
       	win.addEventListener('click', function() {
       		create();
       	});
           
          win.open();
           
       }
       
       
       create();
       
    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).
  2. Ping Wang 2012-08-15

    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.
       var win = Ti.UI.createWindow({
       	backgroundColor : '#000'
       });
       
       var button = Ti.UI.createButton({
       	title: 'Create picker with 30 rows'
       });
       
       
       button.addEventListener('click', function() {
       
       	var data = [];
       	
       	for (var i = 0; i < 30; ++i) {
       		data[i] = Ti.UI.createPickerRow({
       			title : 'Row ' + i
       		});
       	}
       
       	var picker = Ti.UI.createPicker({top: 50});
       
       	var start = new Date();
       	
       	picker.add(data);
       
       	Ti.API.info('************* Finished: ' + (new Date() - start));
       
       	win.add(picker);
       });
       
       win.add(button);
       
       win.open(); 
       
  3. Ivan Skugor 2012-08-16

    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):
       var j = 0;
       
       function create() {
       	var win = Ti.UI.createWindow({
       		backgroundColor: '#000',
       		navBarHidden: true
       	});
       	var data = [];
       	var start = new Date();
       
           Ti.API.info(j);
       	for (var i = j; i < (j + 30); ++i) {
       		data.push(Ti.UI.createPickerRow({ title: 'Row ' + i }));
       		// data.push(Ti.UI.createTableViewRow({ title: 'Row ' + i, className: 'Row' }));
       	}
       	Ti.API.info('Rows: ' + (new Date() - start));
       	var picker = Ti.UI.createPicker();
       	// var table = Ti.UI.createTableView();
       	start = new Date();
       	picker.add(data);
       	// table.setData(data);
       	Ti.API.info('Finished: ' + (new Date() - start));
       	win.add(picker);
       	// win.add(table);
       	j = j + 30;
       	win.addEventListener('open', function() {
       		Ti.API.info('OPEN: ' + (new Date() - start));
       	});
       	win.addEventListener('click', function() {
       		create();
       	});
       	win.open(); 
       }
       
       create();
       
  4. Ping Wang 2012-08-17

    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.
  5. Ivan Skugor 2012-08-20

    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.
       function create() {
       	
           var win = Ti.UI.createWindow({
               backgroundColor: '#000',
       		layout: 'vertical',
               navBarHidden: true
           });
           
           var start = new Date();
       
       	for (var j = 0; j < 5; ++j) {
       		var data = [];
       	    for (var i = 0; i < 30; ++i) {
       	        data.push(Ti.UI.createPickerRow({ title: 'Row ' + i }));
       	        // data.push(Ti.UI.createTableViewRow({ title: 'Row ' + i, className: 'Row' }));
       	    }
       	    var picker = Ti.UI.createPicker();
       	    // var table = Ti.UI.createTableView();
       	    picker.add(data);
       	    // table.setData(data);
       	    win.add(picker);
                   // win.add(table);
       	}
       
           
           win.addEventListener('open', function() {
               Ti.API.info('OPEN: ' + (new Date() - start));
           });
           win.addEventListener('click', function() {
               create();
           });
           win.open(); 
       }
       
       create();
       
    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.
  6. Neeraj Gupta 2012-08-20

    I agree that it should not take 8 seconds in this scenario. We need to investigate this issue further.
  7. Josh 2012-09-07

    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.
  8. Shak Hossain 2012-10-19

    Escalating it for Homes.com.
  9. Anirudh Nagesh 2012-10-19

    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.
  10. Karl Rowley 2012-10-29

    Pull request https://github.com/appcelerator/titanium_mobile/pull/3351
  11. Karl Rowley 2012-10-30

    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.
  12. Karl Rowley 2012-10-30

    Re-opening pending pull request for 3_0_X branch
  13. Karl Rowley 2012-10-30

    Pull request https://github.com/appcelerator/titanium_mobile/pull/3361 for 3_0_X branch
  14. Natalie Huynh 2012-12-05

    Tested with 3.0.0.v20121204144658 on Droid 1 2.2.3

JSON Source