The Coding Wombat
The Coding Wombat

Reputation: 815

ExceptionInInitializerError with enums in libGDX

I have the following enum file "DevelopmentCardType":

enum DevelopmentCardType {
    KNIGHT (0, new Texture(Gdx.files.internal("knight_card.png")));
    VICTORY_POINT (1, new Texture(Gdx.files.internal("victory_point_card.png"))),

    private final Texture cardTexture;
    private final int type;
    private static final List<DevelopmentCardType> VALUES = Collections.unmodifiableList(Arrays.asList(values()));

    DevelopmentCardType(int type, Texture cardTexture) {
        this.type = type;
        this.cardTexture = cardTexture;
    }

    public Texture getCardTexture() {
        return cardTexture;
    }

    public static List<DevelopmentCardType> getVALUES() {
        return VALUES;
    }
}

upon a socket event a new DevelopmentCard is created

"DevelopmentCard" class:

class DevelopmentCard extends Card {

  private float[] vertices = {
        0, 0,
        512, 0,
        512, 512,
        0, 512
  };

  DevelopmentCard (int type) {
    super(0, 0, 70, 100);
    this.type = type;
    createResourceCardSprite(type);
  }

  private void createResourceCardSprite(int resourceType) {
    Texture cardTexture = DevelopmentCardType.getVALUES().get(resourceType).getCardTexture();
    TextureRegion textureRegion = new TextureRegion(cardTexture);
    PolygonRegion polygonRegion = new PolygonRegion(textureRegion, vertices, new EarClippingTriangulator().computeTriangles(vertices).toArray());
    card = new PolygonSprite(polygonRegion);
  }
}

When a new DevelopmentCard is created, it creates an ExceptionInInitializerError "caused by" there not being an OpenGL context.

This means the textures that are used in the enum aren't created yet, so that's why I want to do that before first using the enum upon a socket event. I can fix it by adding an init method to the DevelopmentCardType class like (I understand that calling any method (which may be empty like this one) in the enum while still in the OpenGL context will fix the problem, I'm not sure whether this is the right thing to do):

static void init() {}

and calling this in class "Main" like DevelopmentCardType.init();.

Is this the correct way to get around this problem? I can also fix the problem by creating a DevelopmentCard while still in the OpenGL context, after that, creating new DevelopmentCard instances does not result in errors.

Upvotes: 0

Views: 291

Answers (1)

Tenfour04
Tenfour04

Reputation: 93789

There are two requirements to instantiate a Texture. It must be done on the GL thread, and it must be done after LibGDX is initialized.

The first time DevelopmentCardType is referenced anywhere, it will instantiate all its values (KNIGHT and VICTORY_POINT). This is likely occurring before the Gdx engine is initialized (which happens when you call initialize in your DesktopLauncher or AndroidLauncher). It is also likely occurring in a different thread than the GL thread if DevelopmentCardType is used anywhere outside your create() and render() methods (such as in the constructor, or as a member variable).

Furthermore, it does not make sense for an enum to handle the loading of an asset (the textures), which are transient objects and cause memory leaks when not disposed properly.

Really you should handle all your assets for your game in one place so you can easily manage loading and unloading, and avoid memory leaks. LibGDX already has a powerful class for doing that, AssetManager. If you want to keep a similar structure to your current code, I suggest replacing the Texture member of your enum with a String for the file name of the Texture. This can be used to retrieve the Texture from your AssetManager. You can pass your AssetManager instance to your DevelopmentCard constructor so it can retrieve the Texture.

Upvotes: 1

Related Questions