[ANDROID] Loader for images not working on 2.8.2?

As simple as that:
loading the image works great on lime 2.7.0, openfl 3.4.0
Application crashes on lime 2.8.2 / openfl 3.5.3.

Tried the same with Assets.getBitmapData(), Crashes on 2.8.2 / 3.5.3. Works on 2.7.0 / 3.4.0.
Reproduce with this simple code (url is just something off google…):

        var onLoaderComplete = function(e:Dynamic):Void { trace("complete"); };
        var onLoaderEror = function(e:Dynamic):Void { trace("error!"); };
        
        var _loader:Loader = new Loader();
        _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
        _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoaderEror);
        
        _loader.load(new URLRequest("http://i.telegraph.co.uk/multimedia/archive/02625/mountain1_2625884k.jpg"));
        
        addChild(_loader);

Hi, I’ve found that the Loader class is not so good when we use targets other than Flash. I’ve been using a workaround for it with the URLLoader class. This one works ok on all targets I tested, with the latest version of Lime/OpenFL. Here is the code I’m using:

// prepare loader
        this._loader = new URLLoader();
        this._loader.dataFormat = URLLoaderDataFormat.BINARY;
        this._loader.addEventListener(Event.COMPLETE, onLoaderComplete);
        this._loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onLoaderHttpStatus);
        this._loader.addEventListener(Event.UNLOAD, onLoaderUnload);
        this._loader.addEventListener(IOErrorEvent.IO_ERROR, onLoaderIoError);
        this._loader.addEventListener(ProgressEvent.PROGRESS, onLoaderProgress);
        // prepare display
        #if flash
            // I use the Loader itself on Flash target and Bitmap for the other ones
            this._graphicFL = new Loader();
            this._graphicFL.contentLoaderInfo.addEventListener(Event.COMPLETE, onFLLoaderComplete);
            this.addChild(this._graphicFL);
        #else
            this._graphic = new Bitmap();
            this.addChild(this._graphic);
        #end

In order to check the loading process, I’m using:

private function onLoaderComplete(evt:Event):Void
    {
        #if flash
            // the Flash Loader class dispatches the COMPLETE event when the bitmap data is loaded
            this._graphicFL.loadBytes(this._loader.data);
        #else
            if (this._graphic.bitmapData != null) this._graphic.bitmapData.dispose();
            #if lime_legacy
                this._graphic.bitmapData = BitmapData.loadFromBytes(this._loader.data);
            #else
                this._graphic.bitmapData = BitmapData.fromBytes(this._loader.data);
            #end
            // I had no other option here - just start a timer to check when the bitmap data becomes available
            // any other ideas?
            this._timer = new Timer(100);
            this._timer.run = this.checkBitmapLoad;
        #end
    }
    
    private function checkBitmapLoad():Void
    {
        // data loaded on the Bitmap object
        if ((this._graphic.bitmapData.width != 0) && (this._graphic.bitmapData.height != 0)) {
            // do whatever you need
            this._timer.stop();
            this._timer = null;
        }
    }
    
    private function onFLLoaderComplete(evt:Event):Void
    {
       // do whatever you need
    }

I’m currently working on some classes to simplify the dynamic media load (picture, video, audio and text). I’m getting some good results on Flash and HTML5 targets right now - the ones I’ll be using.

I don’t know if it is HXCPP, or the newer Android NDK, or a combination, but I found under some circumstances, loading multiple files (audio or image files, I believe) in succession would cause a crash. This was a race condition, with bytes data being garbage collected too soon.

I found a fix and published it to the Lime GitHub today. I wonder if this is what is affecting your project? Thanks

EDIT: Nevermind, still more issues :cry:

Alright, seems to be sorted on the repositories, Android image/audio loading working properly

Thats great! Was it gc issue?

It was too issues.

Yes, it was a deallocation, but in C++, not in Haxe. The first issue was like this:

char* ptr = 0;

if (true) {
   
    TemporaryType type = TemporaryType ();
    ptr = type.Data ();
   
}

// do something with ptr

With all former compiler versions we’ve used, TemporaryData would be kept in scope until the end of the function, but on the newer toolchain with Android, it is dumped after leaving the if statement, causing the remaining pointer to fail.

You can fix it for most types like this:

char* ptr = 0;
TemporaryType type;

if (true) {
   
    type = TemporaryType ();
    ptr = type.Data ();
   
}

…but our Bytes type in C++ was behaving strangely when does this way, I’m not 100% sure why, but using it on the stack fixed it:

char* ptr = 0;
TemporaryType type = 0;

if (true) {
   
    type = new TemporaryType ();
    ptr = type->Data ();
   
}

// do something with ptr

if (type) delete type;

This was quite scary/strange to track down, and difficult because it only occurred on Android :confused:

1 Like