Operating System
Name = Mac OS X
Version = 10.11
Architecture = 64bit
# CPUs = 8
Memory = 17179869184
Node.js
Node.js Version = 0.10.38
npm Version = 1.4.28
Titanium CLI
CLI Version = 4.1.5
Titanium SDK
SDK Version = 5.0.2.GA / 5.2.0.v20151008212033
SDK Path = /Volumes/Data/Users/sebastian/Library/Application Support/Titanium/mobilesdk/osx/5.2.0.v20151008212033
Target Platform = iphone
I found a behaviour in the newest SDKs which are not reproducible but good comparable with the actual GA SDK. I made two videos for better visualization.
The same behaviour exists, when I call a function instead of the "self eventlistener".
5.0.2.GA
http://cl.ly/image/0A2v2D1E0i3P
5.2.0.v20151008212033
http://cl.ly/image/1j2M2S1M1f3w
var refreshBtn = Ti.UI.createButton({
systemButton: Ti.UI.iPhone.SystemButton.REFRESH
});
// creating the window
var self = Ti.UI.createWindow({
title: 'event test',
backgroundColor: '#fff',
rightNavButton: refreshBtn
});
refreshBtn.addEventListener('click', function () {
self.fireEvent('refreshList', {});
});
var navController = Ti.UI.iOS.createNavigationWindow({
window: self
});
// the progressbar I expect to see
var progressLoadingBar = Ti.UI.createProgressBar({
width: '80%',
color: '#000',
font: {
fontSize: 14
},
min: 0,
max: 0,
value: 0
});
self.add(progressLoadingBar);
var listViewItemsCount = 10000, itemsArray = [];
var listView = Ti.UI.createListView({});
// showing the listView
self.addEventListener('refreshList', function () {
//Hide listView to show indicator
listView.hide();
// resetting the progressBar
progressLoadingBar.setValue(0);
progressLoadingBar.setMax(listViewItemsCount);
// show the progressbar
progressLoadingBar.show();
var section = Ti.UI.createListSection({});
// adding the items
for (var i = 1; i < listViewItemsCount; i++) {
itemsArray.push({
properties: {
itemId: i,
title: 'Item ' + i,
subtitle: 'Subtitle for item ' + i
},
template: Ti.UI.LIST_ITEM_TEMPLATE_SUBTITLE
});
progressLoadingBar.setValue(i);
}
section.setItems(itemsArray);
listView.setSections([section]);
// show the listview
listView.show();
// hide the progressbar
progressLoadingBar.hide();
});
// listen to the event
self.fireEvent('refreshList', {});
navController.open();
There's a lot of different parts to the test case you provided. You say _The same behaviour exists, when I call a function instead of the "self eventlistener"._. Could you try to minimalist the use case so it's more precise, easier to track and quicker to fix?
It seems, that the code within a eventListener or a function will be completely executed and after finishing all work, the view actions are executed. As an example: I have a loading window with a progressbar for an export function. I start the export, nothing happens (no overlay with progressbar is shown). then, after doing all databse operations and file writings, the overlay flashes short with a progressbar 100% filled. The example code show the problem. All code excepting the code which is responsible for the views is executed one by one. The code, which is responsible for the views, seems to be executed at the end and all of my commands at the same time. I hope, I described it more clearly now.
[~cng] [~penrique] can this be a side effect of TIMOB-18976 which is now default in SDK 5.1? (TIMOB-19682)
I just tested to set the this.runOnMainThread = false in the iphone/cli/commands/_build.py This has no effect building with 5.2.0.v20151014151229 But I don't really know if this would be the only change I have to do. Was just trying out.
Please try disabling it for testing purposes using the tiapp.xml:
That will disable it inside the SDK itself. I didn't thought about Fokke's idea, but is really seems like the only thing that changed and might effect this behavior. Give it a try!
Yes, that did it. But of course I want to use with runOnMainThread = true. It's a huge performance difference. Do you have any code example how I can figure out that?
[~benutzername] With the JS engine being on the main thread, you no longer have async UI updates. You will need to change your code to workaround this. This means splitting up workloads. Say you have an array of 100 items and for each item you want to do some work on it and update a progress bar. You will need to change your code so that the one unit of work is done in a recursive function that continually calls itself until all items are processed. The trick is you need to wrap nested calls in a
setTimeout()
.setTimeout()
will cause the JS engine to schedule a continuation on the next tick and gives the UI a chance to update and events to be handled.Verified fixed, using: MacOS 10.11.2 (15C27e) Studio 4.4.0.201510280736 Ti SDK 5.1.0.v20151028190028 Appc NPM 4.2.1 Appc CLI 5.1.0-38 Ti CLI 5.0.5 Alloy 1.7.16 Arrow 1.3.13 Xcode 7.2 (7C46l) Node v0.12.7 Java 1.7.0_80 production Used the sample code provided to test. Progress bar is shown as expected, on load, due to not running on the main thread, by default.