Search code examples
javalibgdx

Is referencing Styles, fonts and images from static class bad?


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);

Solution

  • 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).