0

I have a game which does not/cannot use a "Loading Screen". I'm having some trouble using AssetManager to load assets on the fly after an Ad shows, or an IAP process happens - essentially whenever the OpenGL context changes.

I've followed the wiki article on AssetManager, but I'm still seeing black textures whenever I try to load a "new" texture.

I have a Singleton custom GameAssetManager which has some convenience methods which delegate to LibGDX's AssetManager.

For example:

public Texture getTexture(String filename) {
    if (assets.isLoaded(filename)) {
        return assets.get(filename, Texture.class);
    } else {
        assets.load(filename, Texture.class);
        assets.finishLoadingAsset(filename);
        Texture texture = assets.get(filename, Texture.class);
        sessionAssets.put(filename, texture);
        return texture;
    }
}

In my AndroidLauncher, I override the onResume method like so:

@Override
protected void onResume() {
    super.onResume();
    GameAssetManager.instance.resume();
}

The GameAssetManager.resume() method just does this:

public void resume() {
    assets = new AssetManager();
    Texture.setAssetManager(assets);
}

I have a StoreItemButton which is a Group and which changes it's layout/ui-components when the item is purchased through Google's IAB library or an Ad shows.

After the Ad shows, or the IAB process completes AndroidLauncher.onResume is called and when the button changes it's UI it or parts of it just turn black.

If I go through and pre-load all possible layouts - up to 4 per button (up to 30 buttons), and then just show/hide them based on the situation, it seems to work, but this is a lot of overhead and error prone for no good reason.

Any help here would be greatly appreciated.

Townsfolk
  • 1,282
  • 1
  • 9
  • 21
  • 1
    Why do you need a singleton and why do you need to override the AndroidLauncher#onResume method? Those are two things you shouldn't need to do (as you've probably already read in the wiki page you linked to). – Xoppa Oct 26 '16 at 22:58
  • The singleton is a convenience because I have a lot of custom UI components that load/get their own assets. I could pass along an instance of my custom `GameAssetManager` where ever I instantiate a new UI component, but if the context changes and the underlying `AssetManager` delegate doesn't work anymore, how would that help in this situation? As for overriding AndroidLaucher#onResume the wiki article says I need to create a new AssetManager and set it in Texture when the application resumes. https://github.com/libgdx/libgdx/wiki/Managing-your-assets#resuming-with-a-loading-screen – Townsfolk Oct 26 '16 at 23:12
  • I know the article says "With a loading screen", but I figured it should be updated even if I'm not using a loading screen. – Townsfolk Oct 26 '16 at 23:13
  • 1
    Using singleton on Android is never a convenience. Without seeing your sscce, its impossible to tell, but its very likely that your issue is caused by using statics. Either way, it certainly has nothing to do with "context changes". You might want to read that wiki page again if you still think you should use singleton. – Xoppa Oct 26 '16 at 23:27
  • Ok, I've swapped out the Singleton, but it's still happening albeit much less. Now it seems to be specialized to the use of ImageButtonStyles. I have one place where I initialize 3 different styles and then swap them into a button at run-time depending on a user action. If I show them in one state, go to a different Screen, show an ad, then return and show them in the new state, they are blacked out. I've tried re-loading the textures anew before the buttons are visible, no luck. Any ideas? – Townsfolk Oct 27 '16 at 02:57
  • As said, you should not be doing anything in your `onResume` or `resume` methods. Other than that, we can't tell you whats wrong with your code without seeing your code. Have a look at: http://stackoverflow.com/help/mcve. – Xoppa Oct 27 '16 at 16:20

1 Answers1

0

The short explanation is that while your application may see texture references on the JVM heap as valid, the real texture bytes in the GPU may be invalid.

This often happens onPause, because another activity or process may take the OpenGL context to draw itself and everything that your program has put to the GPU may be discarded. When the program resumes after that (onResume), your variables holding the textures may not be destroyed and may still point to valid JVM heap objects (either because you have static refs, or because the Gargabe Collector has not claimed anything), but the textures in the GPU are gone and should be pushed/reloaded there again.

This is the article that can give you a more complete answer, directly by the libgdx "benevolent dictator" :)

http://www.badlogicgames.com/wordpress/?p=1073

luben
  • 2,512
  • 4
  • 30
  • 41
  • 1
    This is incorrect. The issue is caused by a bad design (using `static` without properly managing it) which doesn't cope with the JVM being reused on Android. It is *not* caused by an opengl context loss (which will never happen unless you have an ancient device). If you read the page you referred to then you'll read that libgdx actually "fixes" those context losses (which wont happen anymore) for you. Please see http://badlogicgames.com/forum/viewtopic.php?f=11&t=20757&p=86095#p86095, where I explain this in depth. – Xoppa Dec 02 '16 at 19:05
  • Thank you for the comment. This is my understanding of the opengl context story and it's not based on very deep experience with low-level opengl stuff, so it's very probable to be incorrect. But I wonder, what do you mean by not properly managing statics? If I have a static texture reference STR, isn't it the case that STR is either (1) null, (2) valid reference to a texture in the heap and the GPU, (3) valid reference to a texture in the heap, but invalid on the GPU? – luben Dec 03 '16 at 07:34
  • @Xoppa And thank you for the link and the informative description of how the GPU handles multiple contexts. – luben Dec 03 '16 at 13:47
  • 1
    Statics dont have the same lifecycle as your application; multiple instances of your application can use the same static variables. I'm afraid comments aren't very suited to go further in depth on that. You could consider asking a new question for that or catch me on IRC. https://github.com/libgdx/libgdx/wiki/Getting-Help – Xoppa Dec 03 '16 at 18:52