Nasser Tahani
Nasser Tahani

Reputation: 735

Android Libgdx memory leak on creating Actors

I've created an Android application to show about a hundred point objects using Libgdx modelBuilder. It works fine and models are rendered without any problem, but I needed to add a marker for every point model. To do that I've extended from Actor and in this class, I've created two textures representing the marker in normal and the selected mode when the user clicked the objects. The following is the LabelActor class which has been instantiated for each point model.

public class LabelActor extends Actor {

    Texture texture;
    Texture selectedTexture;
    Sprite sprite;
    private Vector3 distVector = new Vector3();

    public LabelActor( String markerColor){

        String path = "markers/point_marker_" + markerColor + ".png"";
        String selected_path = "markers/point_marker_select.png";
        texture = new Texture(Gdx.files.internal(path));
        selectedTexture = new Texture(Gdx.files.internal(selected_path));
        sprite = new Sprite(texture);
        setBounds(sprite.getX(), sprite.getY(), sprite.getWidth(), sprite.getHeight());
    }

    @Override
    protected void positionChanged() {
        sprite.setPosition(getX(),getY());
        super.positionChanged();
    }


    @Override
    public void draw(Batch batch, float parentAlpha) {

         if (selected){
            batch.draw(selectedTexture, getX()-sprite.getWidth()/2, getY());
        } else {
            batch.draw(texture, getX()-sprite.getWidth()/2, getY());
        }
    }

}

The problem will be arisen on using the marker for these objects which causes a huge amount of memory usage. Loading a sphere model for each point objects takes about 14M of graphics memory but loading texture markers take 500M of memory on the device. I've used png icons located in the asset folders to create my textures but not using a Libgdx atlas. Is there any chance to create markers for this number of point objects to consume a little amount of memory?

Below is the image representing the view of the markers and point models.

enter image description here

Edit 1: I've used AssetManager to load textures and create HashMap of them in the main screen then pass an array of two textures to each LabelActor class as Retron advised, but the memory is still overloaded.

public class LabelActor extends Actor {

    Texture texture;
    Texture selectedTexture;
    Sprite sprite;
    private Vector3 distVector = new Vector3();

    public LabelActor(Texture[] textures){

        texture = textures[0];
        selectedTexture = textures[1];
        sprite = new Sprite(texture);
        setBounds(sprite.getX(), sprite.getY(), sprite.getWidth(), sprite.getHeight());
    }

    @Override
    protected void positionChanged() {
        sprite.setPosition(getX(),getY());
        super.positionChanged();
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {

         if (selected){
            batch.draw(selectedTexture, getX()-sprite.getWidth()/2, getY());
            infoWindow.draw(batch, parentAlpha);
        } else {
            batch.draw(texture, getX()-sprite.getWidth()/2, getY());
        }
    }
}

Part of main screen to load textures using AssetManager:

@Override
public void create() {

    ...
    environment = new Environment();
    environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1.0f));
    pointLight = new PointLight().set(0.8f, 0.8f, 0.8f, 2f, 0f, 0f, 500f);
    environment.add(pointLight);

    assetManager =  new AssetManager();
    textureTitleList = new ArrayList<>();
    for (FileHandle f: Gdx.files.internal("markers").list()){
        assetManager.load("markers/" + f.name(), Texture.class);
        textureTitleList.add(f.name());
    }
}

private void loadModel() {

    textureMap = new HashMap<>();
    for (String fName: textureTitleList){
        textureMap.put(fName, assetManager.get("markers/" + fName, Texture.class));
    }
}

@Override
public void render() {

    if (!isLoaded && assetManager.update()) {
        loadModel();
        isLoaded = true;
    }
    ...
}

Upvotes: 1

Views: 164

Answers (1)

Retron
Retron

Reputation: 129

You must use AssetManager and load ONE texture from asset, not create new texture for every new actor.

Upvotes: 2

Related Questions