Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-17536] Android: createInterval/setInterval crashes app

GitHub Issuen/a
TypeBug
PriorityLow
StatusClosed
ResolutionCannot Reproduce
Resolution Date2017-07-24T22:11:27.000+0000
Affected Version/sRelease 3.3.0
Fix Version/sn/a
ComponentsAndroid
LabelsTCSupport
ReporterMauro Parra-Miranda
AssigneeEric Merriman
Created2014-08-20T22:46:00.000+0000
Updated2017-07-24T22:11:27.000+0000

Description

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

Comments

  1. Ingo Muschenetz 2014-08-20

    Setting as medium due to existence of workaround.
  2. jithinpv 2014-09-19

    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
  3. Lee Morris 2017-07-24

    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

JSON Source