0

I've read a lot about different pitfalls of using static classes, so I never really bothered using one.

However I could see major advantages for me in creating a static class that holds all my styles, images, fonts etc. For easy referencing. Would this be bad for performance or bad design?

To help explain what I mean I have some code, this is from the static class:

    button2Style = new TextButtonStyle();
    button2Style.up = new NinePatchDrawable(buttonAtlas.createPatch("button2"));
    button2Style.down = new NinePatchDrawable(buttonAtlas.createPatch("button2")).tint(Color.GRAY);
    button2Style.font = font_rr_65;
    button2Style.fontColor = Colors.PURPLE;

Then I want to reference it like this in another class:

TextButton txtB = new TextButton("Hello", StaticClass.button2Style);
Green_qaue
  • 3,561
  • 11
  • 47
  • 89
  • It's less general pitfalls of using static classes than incorrect usage of static classes. For a consistent application-wide style, this seems appropriate. – Compass May 18 '16 at 18:05

2 Answers2

3

Although using statics in general usually is a good indication of a bad object oriented design, please note that that even more: Having static references to assets is especially bad, because the life cycle of the statics might not be the same as the life cycle the context the resources are created in.

Let's take the answer of @BasimKhajwal as an example:

class Assets { /*...*/
    private static final AssetManager assetManager = new AssetManager();

When is this code new AssetManager() actually executed? It is executed practically directly after the VM is initialized. So that might be before your application window is actually created or even before all native libraries are loaded and the OpenGL context is created.

public static void loadAll() { /* load things */ }

When is this code executed? You call this probably somewhere in your ApplicationListener's create method. So, the OpenGL context for that specific instance of your application is created and active at that moment and it is called on the render thread of that application.

Now consider the following situation, running on Android:

Your VM static assets are loaded in that application context and you can use them in that context. Then you receive a phone call, causing your application to be pushed in the background. After a while, Android decides that it needs to free up memory and closes your application including its OpenGL context and such.

After you finish your phone call, you go back to your game. So Android starts a new instance of your game. For that it re-uses the same VM of the previous instance of your application, including the same AssetManager and all assets it already has loaded. Your application creates a new OpenGL context etc., but the assets still point to the old invalid context. Thus making your assets invalid and causing undesired behavior.

Of course you won't easily find such problems during normal testing. And there is no guarantee if or when Android will close your application and recycle the VM. But if you give it a few tries you should be able to reproduce above steps, so you can see for yourself how your resources become invalid (e.g. texture become black). It is even said to be possible for multiple instances of your application to be running in the same VM (e.g. when launching from the Play store and the launch screen).

You could work around that problem. For example, libGDX does that internally by keeping a Map of all resources for each instance of application (here's an example if you like to see how it works). But since you are most likely not properly implementing Object Oriented Design to begin with, you're probably better off to reconsider your approach.

If you do still decide to use statics then make sure to fully understand their life-cycle (don't assume they wont outlive, or are exclusive to, that specific instance of your application).

Note that this is probably one of the most made mistakes (next to using "virtual" pixels). If you search a bit you will find quite some examples of people who have issues using statics, especially on Android. Please keep in mind though, that while this exhibits most on Android, it is a design issue. It doesn't mean that it doesn't apply to you when you don't target Android. It is perfectly possible to design your application so that you don't need any static resources (or any static variables of significance at all).

Xoppa
  • 7,983
  • 1
  • 23
  • 34
  • Thanks for correction! I've learnt from this as well, and will incorporate this in my future projects. – Basim Khajwal May 19 '16 at 13:39
  • Am I right in reasoning that, if my `AssetManager` is cleared on the applications `destroy` method (as it does in my projects), that no errors will occur? (None have ever occurred ever to me in Android/Desktop/HTML5) – Basim Khajwal May 19 '16 at 13:49
  • You should properly dispose your assets in the dispose method, but you shouldn't rely on `dispose` to be actually called. Using either eager or lazy initialization will not work, but you can of course create the manager in your `create` method. That wont help for the cases where multiple instances of your application are running though and neither will it solve the actual problem: the bad code design. You should not need to have access to your assets in that many places to begin with. – Xoppa May 19 '16 at 14:56
1

Edit - turns out I'm wrong :(, see Xoppa's answer

Personally, I find using static classes especially useful for libGDX and game development.

If you read articles like this, people tend to frown on static variable usage. The emphasis is on variable since, normally, having a global state that changes can be harder to debug and reason with. When a variable is static any part of your code could be causing those changes leading a bug/crash later on in a completely different part of the program.

For your assets, they will be constant for most of the lifetime of your game which means they won't interfere with your debugging. In addition, your assets will probably have to be loaded for the entire duration of your game, since most games load all assets at startup. Keeping them static will make little difference in memory usage.

For my games, I usually tend to have a static class called Assets which uses the built-in AssetManager class. I can then easily reference any assets using their file paths which are stored as constants. By doing this you ensure that other classes cannot edit your static textures and you can easily iterate over textures.

Example:

class Assets {

    /* Use built-in libGDX asset manager to load/store all assets */
    private static final AssetManager assetManager = new AssetManager();

    /* Use private constructor to prevent instantiation */
    private Assets () { }

    /*
        Public constants to be referenced by other classes
    */
    public static final String BAD_GUY = "images/bad_guy.png";
    public static final String GOOD_GUY = "images/good_guy.png";

    /*
        Private arrays of all textures/sounds/fonts for loading
    */
    private static final String[] TEXTURES = {
        BAD_GUY,
        GOOD_GUY;
    };

    /* Load method for all assets called by your main game handler at start */
    public static void loadAll() {

        //Setup the load queue for all textures 
        for (String texture: TEXTURES)
            assetManager.load(texture, Texture.class);

        //Load everything
        assetManager.finishLoading();

        /* Do all the post processing here */
    }

    /* Access method for textures the parameter name is from above e.g. Assets.BAD_GUY */
    public Texture getTexture(String name) {
        return assetManager.get(name, Texture.class);
    }
}

If you want to see a real-life example you can see my own game file: https://github.com/basimkhajwal/LSD/blob/master/core/src/net/net63/codearcade/LSD/managers/Assets.java

Beware, it is a bit more complex as it contains sounds, animations and some game-specific code but the main principle is the same.

Community
  • 1
  • 1
Basim Khajwal
  • 946
  • 6
  • 6