Problem Description
The customer is using setInterval for animating a loader, when the window that contains the loader is closed, the customer does a clearInterval and the app crashes.
Steps to reproduce
1. Create a new mobile project (classic ttitanium)
2. Paste the code of the testcase:
var win = Titanium.UI.createWindow({
title : 'Test',
backgroundColor : '#fff'
});
var v_progress_bar = Ti.UI.createView ({
left: 10,
right: 10,
height: 10,
backgroundColor: '#333'
});
var v_progress_indicator = Ti.UI.createView ({
left: 0,
width: 0,
top: 0,
bottom: 0,
backgroundColor: '#2F7CC1'
});
v_progress_bar.add (v_progress_indicator);
win.add (v_progress_bar);
var current_fill_width = 0;
var duration = 60000;
var start_time = new Date().getTime ();
function update_position ()
{
var now = new Date().getTime ();
var elapsed = now - start_time;
if (elapsed > duration) {
elapsed = duration;
}
// this should cause a crash after the window is closed...
var fill_width = parseInt (elapsed / duration * v_progress_bar.size.width);
if (fill_width != current_fill_width)
{
Ti.API.info ("setting progress_bar_width...");
v_progress_indicator.setWidth (fill_width);
current_fill_width = fill_width;
}
}
var up_int = setInterval (update_position, 250);
win.addEventListener ('close', function (e) {
Ti.API.info ('win closed.');
clearInterval (up_int);
});
win.open();
3. Run it in a device
4. Once the bar starts loading, click on the back button of the device.
5. The app will crash.
Workarund
The same customer, if rearranges the code like this:
var win = Titanium.UI.createWindow({
title : 'Test',
backgroundColor : '#fff'
});
var v_progress_bar = Ti.UI.createView ({
left: 10,
right: 10,
height: 10,
backgroundColor: '#333'
});
var v_progress_indicator = Ti.UI.createView ({
left: 0,
width: 0,
top: 0,
bottom: 0,
backgroundColor: '#2F7CC1'
});
v_progress_bar.add (v_progress_indicator);
win.add (v_progress_bar);
var current_fill_width = 0;
var duration = 60000;
var start_time = new Date().getTime ();
var progress_bar_width = 0;
function update_position ()
{
var now = new Date().getTime ();
var elapsed = now - start_time;
if (elapsed > duration) {
elapsed = duration;
}
// don't try to access size from within setInterval(); when the window is closed
// on android, you'll get a nasty NullPointerException, even if you try to remove
// the event listener on window close
var fill_width = parseInt (elapsed / duration * progress_bar_width);
if (fill_width != current_fill_width)
{
Ti.API.info ("setting progress_bar_width...");
v_progress_indicator.setWidth (fill_width);
current_fill_width = fill_width;
}
}
// get the size once at startup, and get it any time the orientation changes...
// if we didn't remove the event listener, it would get triggered every time
// we resized the progress indicator, which would mean we'd get triggered
// during the window close; accessing the size property of a view during
// the window close will cause a NullPointer Exception.
function on_new_size (e)
{
Ti.API.info ("checking progress_bar_width...");
progress_bar_width = v_progress_bar.size.width;
Ti.API.info ("progress bar width: " + progress_bar_width);
win.removeEventListener ('postlayout', on_new_size);
}
win.addEventListener ('postlayout', on_new_size);
Ti.Gesture.addEventListener('orientationchange',function(e) {
win.addEventListener ('postlayout', on_new_size);
});
var up_int = setInterval (update_position, 250);
win.addEventListener ('close', function (e) {
Ti.API.info ('win closed.');
clearInterval (up_int);
});
win.open();
will work just fine.
Community Discussion
http://developer.appcelerator.com/question/177097/manipulating-a-view-from-setinterval-callback-crashes-app
Setting as medium due to existence of workaround.
Issue reproduces Titanium SDK version 3.4.0 master, 3.3.0.GA Titanium Studio, build: 3.3.0.201407100905 Titanium Command-Line Interface CLI version 3.3.0, Android device : Motorola Moto G, Android version : 4.4.4
I am unable to reproduce this issue with the following environment; Pixel (7.1) Studio 4.9.0.201705302345 Ti SDK 6.1.1 GA Appc NPM 4.2.9 Appc CLI 6.2.2 Ti CLI 5.0.14 Alloy 1.9.11 Xcode 8.2 (8C38) Node v4.8.2 Java 1.8.0_131