0

This method takes images from the in-built gallery and submits them to the screen in form of a Texture. I also store their choosen image in a file to be presented everytime the user enters that screen. The issue is that when I upload, lets say 3 images in a row I receive memory warning in console, later leading to the app crashing due to memory error:

AppLauncher failed with an exception: java.lang.RunTimeException: The app crashed: Terminated due to Memory Error

It's hard to pinpoint the exact reason for this. But I've debugged and logged a bit and it doesn't seem that the writing of the image to a file is causing it. It's more related to the action of removing an already existing Image and then uploading a replacement. When I let the user delete their image, the whole file is deleted and the texture is disposed. I also noticed that when the user have uploaded some images and exit the screen, it crashes with that memory error.

    FileHandle fileIOS1 = Gdx.files.external("iosImage1.png");
    FileHandle fileIOS2 = Gdx.files.external("iosImage2.png");
    FileHandle fileIOS3 = Gdx.files.external("iosImage3.png");
    FileHandle fileIOS4 = Gdx.files.external("iosImage4_.png");
    FileHandle fileIOS5 = Gdx.files.external("iosImage5.png");
    FileHandle fileIOS6 = Gdx.files.external("iosImage6.png");
    FileHandle fileIOS7 = Gdx.files.external("iosImage7.png");
    FileHandle fileIOS8 = Gdx.files.external("iosImage8.png");
    FileHandle fileIOS9 = Gdx.files.external("iosImage9.png");
    FileHandle fileIOS10 = Gdx.files.external("iosImage10.png");
    FileHandle fileIOS11 = Gdx.files.external("iosImage11.png");
    FileHandle fileIOS12 = Gdx.files.external("iosImage12.png");

    public GalleryScreen(MainClass game) {
    if(game.isIOS()){
        if(fileIOS1.exists()) {
            imageSelected1 = new Texture(fileIOS1);
        }
        if(fileIOS2.exists()) {
            imageSelected2 = new Texture(fileIOS2);
        }
        if(fileIOS3.exists()) {
            imageSelected3 = new Texture(fileIOS3);
        }
        if(fileIOS4.exists()) {
            imageSelected4 = new Texture(fileIOS4);
        }
        if(fileIOS5.exists()) {
            imageSelected5 = new Texture(fileIOS5);
        }
        if(fileIOS6.exists()) {
            imageSelected6 = new Texture(fileIOS6);
        }
        if(fileIOS7.exists()) {
            imageSelected7 = new Texture(fileIOS7);
        }
        if(fileIOS8.exists()) {
            imageSelected8 = new Texture(fileIOS8);
        }
        if(fileIOS9.exists()) {
            imageSelected9 = new Texture(fileIOS9);
        }
        if(fileIOS10.exists()) {
            imageSelected10 = new Texture(fileIOS10);
        }
        if(fileIOS11.exists()) {
            imageSelected11 = new Texture(fileIOS11);
        }
        if(fileIOS12.exists()) {
            imageSelected12 = new Texture(fileIOS12);
        }
    }

    @Override
    public void show() {
    if(game.isIOS()){
        if(fileIOS1.exists()) {
            selected1 = new TextureRegionDrawable(new TextureRegion(imageSelected1));
            style2.up = skin.newDrawable(skin.newDrawable(selected1));
            style2.down = skin.newDrawable(skin.newDrawable(selected1));
        }

        if(!fileIOS1.exists()){
            style2.up = skin.newDrawable(skin.newDrawable(temp));
            style2.down = skin.newDrawable(skin.newDrawable(temp));
        }
        if(fileIOS2.exists()) {
            selected2 = new TextureRegionDrawable(new TextureRegion(imageSelected2));
            style3.up = skin.newDrawable(skin.newDrawable(selected2));
            style3.down = skin.newDrawable(skin.newDrawable(selected2));
        }

        if(!fileIOS2.exists()){
            style3.up = skin.newDrawable(skin.newDrawable(temp));
            style3.down = skin.newDrawable(skin.newDrawable(temp));
        }
        if(fileIOS3.exists()){
            selected3 = new TextureRegionDrawable(new TextureRegion(imageSelected3));
            style4.up = skin.newDrawable(skin.newDrawable(selected3));
            style4.down = skin.newDrawable(skin.newDrawable(selected3));
        }
        if(!fileIOS3.exists()){
            style4.up = skin.newDrawable(skin.newDrawable(temp));
            style4.down = skin.newDrawable(skin.newDrawable(temp));
        }
    Gdx.app.log("HERE:", "6");
        if(fileIOS4.exists()){
            selected4 = new TextureRegionDrawable(new TextureRegion(imageSelected4));
            style5.up = skin.newDrawable(skin.newDrawable(selected4));
            style5.down = skin.newDrawable(skin.newDrawable(selected4));
        }
    Gdx.app.log("HERE:", "7");
        if(!fileIOS4.exists()){
            style5.up = skin.newDrawable(skin.newDrawable(temp));
            style5.down = skin.newDrawable(skin.newDrawable(temp));
        }
        if(fileIOS5.exists()){
            selected5 = new TextureRegionDrawable(new TextureRegion(imageSelected5));
            style6.up = skin.newDrawable(skin.newDrawable(selected5));
            style6.down = skin.newDrawable(skin.newDrawable(selected5));
        }
        if(!fileIOS5.exists()){
            style6.up = skin.newDrawable(skin.newDrawable(temp));
            style6.down = skin.newDrawable(skin.newDrawable(temp));
        }
        if(fileIOS6.exists()){
            selected6 = new TextureRegionDrawable(new TextureRegion(imageSelected6));
            style7.up = skin.newDrawable(skin.newDrawable(selected6));
            style7.down = skin.newDrawable(skin.newDrawable(selected6));
        }
        if(!fileIOS6.exists()){
            style7.up = skin.newDrawable(skin.newDrawable(temp));
            style7.down = skin.newDrawable(skin.newDrawable(temp));
        }

    if(fileIOS7.exists()){
        selected7 = new TextureRegionDrawable(new TextureRegion(imageSelected7));
        style8.up = skin.newDrawable(skin.newDrawable(selected7));
        style8.down = skin.newDrawable(skin.newDrawable(selected7));
    }
    if(!fileIOS7.exists()){
        style8.up = skin.newDrawable(skin.newDrawable(temp));
        style8.down = skin.newDrawable(skin.newDrawable(temp));
    }
    if(fileIOS8.exists()){
        selected8 = new TextureRegionDrawable(new TextureRegion(imageSelected8));
        style9.up = skin.newDrawable(skin.newDrawable(selected8));
        style9.down = skin.newDrawable(skin.newDrawable(selected8));
    }
    if(!fileIOS8.exists()){
        style9.up = skin.newDrawable(skin.newDrawable(temp));
        style9.down = skin.newDrawable(skin.newDrawable(temp));
    }
    if(fileIOS9.exists()){
        selected9 = new TextureRegionDrawable(new TextureRegion(imageSelected9));
        style10.up = skin.newDrawable(skin.newDrawable(selected9));
        style10.down = skin.newDrawable(skin.newDrawable(selected9));
    }
    if(!fileIOS9.exists()){
        style10.up = skin.newDrawable(skin.newDrawable(temp));
        style10.down = skin.newDrawable(skin.newDrawable(temp));
    }
    if(fileIOS10.exists()){
        selected10 = new TextureRegionDrawable(new TextureRegion(imageSelected10));
        style11.up = skin.newDrawable(skin.newDrawable(selected10));
        style11.down = skin.newDrawable(skin.newDrawable(selected10));
    }
    if(!fileIOS10.exists()){
        style11.up = skin.newDrawable(skin.newDrawable(temp));
        style11.down = skin.newDrawable(skin.newDrawable(temp));
    }
    if(fileIOS11.exists()){
        selected11 = new TextureRegionDrawable(new TextureRegion(imageSelected11));
        style12.up = skin.newDrawable(skin.newDrawable(selected11));
        style12.down = skin.newDrawable(skin.newDrawable(selected11));
    }
    if(!fileIOS11.exists()){
        style12.up = skin.newDrawable(skin.newDrawable(temp));
        style12.down = skin.newDrawable(skin.newDrawable(temp));
    }
    if(fileIOS12.exists()){
        selected12 = new TextureRegionDrawable(new TextureRegion(imageSelected12));
        style13.up = skin.newDrawable(skin.newDrawable(selected12));
        style13.down = skin.newDrawable(skin.newDrawable(selected12));
    }
    if(!fileIOS12.exists()){
        style13.up = skin.newDrawable(skin.newDrawable(temp));
        style13.down = skin.newDrawable(skin.newDrawable(temp));
    }
}boxImage1.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {

                    if(!fileIOS1.exists()) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                gallery.iosPickImage1();
                                Gdx.app.postRunnable(new Runnable() {
                                    @Override
                                    public void run() {
                                        imageSelected1 = new Texture(fileIOS1);

                                        selected1 = new TextureRegionDrawable(new TextureRegion(imageSelected1));

                                        style2.up = skin.newDrawable(skin.newDrawable(selected1));
                                        style2.down = skin.newDrawable(skin.newDrawable(selected1));
                                    }
                                });
                            }
                        }).start();
                    }
                    if(!fileIOS2.exists()) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                gallery.iosPickImage2();
                                Gdx.app.postRunnable(new Runnable() {
                                    @Override
                                    public void run() {
                                        Gdx.app.log("CREATING IMAGE" , "1");
                                        imageSelected2 = new Texture(fileIOS2);
                                        Gdx.app.log("CREATING IMAGE" , "2");
                                        selected2 = new TextureRegionDrawable(new TextureRegion(imageSelected2));
                                        Gdx.app.log("CREATING IMAGE" , "3");
                                        style3.up = skin.newDrawable(skin.newDrawable(selected2));
                                        style3.down = skin.newDrawable(skin.newDrawable(selected2));
                                    }
                                });
                            }
                        }).start();
                    }
Benni
  • 969
  • 1
  • 19
  • 29

1 Answers1

1

First of all fix your typo public GalleryScreen(MainClass gam**e** ), secondary you are doing like 12 times the same thing which is memory consuming depending on the image size. Imagine you load 12 Images of 12mb each. Sure this will need alot of memory especially if you decode them to a drawable. If you would just load them as they are you would already consume 144mb of ram which is alot! Decoded they might be way bigger!

Here are some hints which should help

  1. First of write a clean method, which loads an image and resizes it to a thumbnail to show. Use a final local variable for the huge image, may call the GC manually after you loaded some pictures and resized them. Try to avoid the GC call but sometimes it may be needed. Take a look into: why-is-it-bad-practice-to-call-system-gc
  2. Clean your code write methods. You are checking if the image exists but why do you check it doulbe? If it exist its loaded so if its loaded you don’t need to check it again since it's in memory as an object. Why don’t you load it directly into a TextureRegionDrawable?
  3. Moreover don’t do 12 member variables of the same type. Use a ArrayList and write dynamic code. Else you'll have to check the whole Code again if you change something to the picture count.
  4. libgdx is not threadsafe. Spawn a runnable in a runnable might not be a good choice. The runnable in libgdx get started before the next frame. So nothing parallele here so there is no need to spawn a thread to post a runnable. Take a look into the desktop backend app: Dektop backend Frame method
  5. Do not spawn threads on a mobile device if you do not need to. You got the pictures loaded in memory and still spawn a thread to put them to the box. This doesn‘t make sense if they are loaded.
Community
  • 1
  • 1
bemeyer
  • 6,154
  • 4
  • 36
  • 86
  • Appreciate your input! 1. What would be a "clean" method? GC = Garbage Collector? How to call it? 2. Load the "file" directly into the TRD? 3. This is where my lack of formal education pulls me back. Im not very fond with Array's, or writing dynamic code for that manner. 4/5. Okey. I just took that method from libgdx's wiki. It fitted well since I wanted to open the gallery in one thread for the user to pick an image, and a postRunnable for when they were done and to then write the selected image to a Texture. – Benni Aug 30 '15 at 13:02
  • To maintain one method which does all the stuff you do with one picture is simple instead of maintaining all the code you wrote. `System.gc()` dont forget that this is bad practise but in some cases it is needed. Es direkt into TRD for example like this: `selected1 = new TextureRegionDrawable(new TextureRegion(new Texture(fileIOS1)));` Yes libgdx uses this to post runnables for the next frame but it's not parallel. On the Arraylist and dynamic methods you need to work since this is awefull to read and maintain. Try to avoid writing the same thing twice. – bemeyer Aug 30 '15 at 13:06
  • so one method should still just handle one image? Just that I handle the whole "put file content on the screen" in one place? If I understood you correctly? – Benni Aug 30 '15 at 16:42
  • right, and you call it for every picture you load, it creates the thumbnail and put it on screen. So if there is a bug or anything else you can fix it by changing this one method instead of reviewing 100 Lines of code. (something like `loadPicture(String filename){...}` – bemeyer Aug 30 '15 at 16:44