Titanium Community Questions & Answer Archive

We felt that 6+ years of knowledge should not die so this is the Titanium Community Questions & Answer Archive

How can I deal with a memory leak when reading httpclient download progress from ondatatream on Android

Below is a working sample of code I am using to test downloads on an android 3.1 tablet.

For simplicity sake rather then downloading several different files it currently tries to download the same file 1000 times, and I have left out all error checking.

All it needs to be used is to set the requestURI variable to the location of a file to download (i.e. "http://…jpg")

Without the ondatastream event it is capable of downloading any number of files (it handled downloading 1000 1Mb jpg files without issue), but with ondatastream the httpclient seems not to be properly cleared and it runs out of memory after only a few repetitions.

I thought maybe that overuse of Ti.Api.info to read the progress may be causing problems but even with this line taken out the device still runs out of memory and the application crashes. As long as I have an ondatastream event handler it crashes every time, even if I do no processing at all within the ondatastream event.

The main issue is that without using ondatastream I can't monitor download progress.

(function(){
    var xhr;
    var reps = 1000;

    function downloadFileList(index)
    {
        Ti.API.info("download: " + index);
        if ( xhr == null ) {
            xhr = Ti.Network.createHTTPClient();
        }

        var requestURI = 'http://upload.wikimedia.org/wikipedia/commons/1/16/AsterNovi-belgii-flower-1mb.jpg';

        xhr.open("GET",requestURI);

        xhr.ondatastream = function(e){
            Ti.API.info(e.progress);
        }

        xhr.onload = function()
        {
            var response = this.responseData;

            var dest = Ti.Filesystem.getFile(Ti.Filesystem.getExternalStorageDirectory(), "file_" + index + ".jpg");

            if (response.type == 1){
                var f = Ti.Filesystem.getFile(response.nativePath);

                if (dest.exists()){
                    dest.deleteFile();
                }

                f.move(dest.nativePath);
                f = null;
            }else{
                dest.write(response);
            }

            dest = null;
            response = null;
            xhr = null;

            if (index < reps){
                downloadFileList(index+1);
            }
        }

        xhr.send();
    }

    downloadFileList(0);
})();
— asked January 23rd 2012 by Liam Manderson
  • android
  • httpclient
  • memory
  • ondatasend
0 Comments

1 Answer

  • I have managed to bypass the issue by using an interval and collecting the file length from the responseheader manually and working out the progress from the current httpclient data length. I then clear the interval in the onload event.

    var xhrProgress = setInterval(function(){
        var total_length = xhr.getResponseHeader("Content-Length");
        var current_length = xhr.responseData.length;
        var progress = current_length/total_length;
    
        Ti.API.info(progress);
    
        total_length = null;
        current_length = null;
        progress = null;
    }, 1000)
    

    then in xhr.onload

    clearInterval(xhrProgress);
    

    This works ok for now, but it would be good to find some answer to why the ondatastream event is causeing the client not to be cleared on Android.

    — answered January 23rd 2012 by Liam Manderson
    permalink
    2 Comments
    • Would really like to know why this is leaking.. have you submitted a JIRA?

      — commented February 22nd 2012 by Mark Henderson
    • Also where do you run this set interval? My xhr does not have a getResponseHeader()

      — commented February 22nd 2012 by Mark Henderson
The ownership of individual contributions to this community generated content is retained by the authors of their contributions.
All trademarks remain the property of the respective owner.