7
\$\begingroup\$

My game does not exit entirely even after calling dispose() method. It loads a black screen when I launch it for the second time and works well if I kill the game manually and restart it.

I get an error that says buffer not allocated with newUnsafeByteBuffer or already disposed when I try to dispose off the SpriteBatch object. This is were I suspect the problem to be. But not able to fix it entirely. Please help!

Here is how I have built it (I have put the sample code here just to show you guys that there are no visible loop backs in dispose function, please correct me if I'm wrong)- In game screen,

public void dispose() {
  AssetLoader.dispose();
  render.dispose();
  Gdx.app.exit(); }

Under class AssetLoader-

public void dispose(){
  Texture.dispose();
  sound.dispose();
}

Under game render class -

public void dispose(){
  spritebatch.dispose(); //throws an error when I GameScreen.dispose is called
  font.dispose();
  shaperender.dispose();
}

I believe that my spritebatch isn't disposing which is causing the black screen but I cannot find a way to dispose it off successfully. Any help would be greatly appreciated.

\$\endgroup\$
2
  • \$\begingroup\$ Are you talking about android? libgdx is multi-platform, so that would be a nice info to have :-) I expect android: Try the following: Start your game and press the home button of the device. The game will NOT be closed - it will supsended. If you start it again it will get RESUMED and not restartet. You may have lost textures - depends on how you implemented it. I cannot remember exactly at the moment, but you need to care for that situation. Normally android decides when to really unload an app not the developer. So you have to care for a resume nevertheless (i.e. incoming phone call etc) .. \$\endgroup\$
    – reiti.net
    Commented Apr 7, 2014 at 15:59
  • \$\begingroup\$ are you actually using "Texture".dispose(); or the <nameOfYourTexture(s)>.dispose(); ? \$\endgroup\$
    – wes
    Commented Apr 7, 2014 at 19:27

4 Answers 4

4
\$\begingroup\$

The body of the dispose() method is not the right place to call the Gdx.app.exit() method. Calling the latter will invoke the call of the former and so you end up with calling dispose() on your objects for the second time. Hint: Read the javadoc of the Gdx.app.exit() method to see exactly what it does.

What you should do is:

  1. Remove the Gdx.app.exit() call from your dispose() method.
  2. You have a hide() method, which is called when your app gets "hidden" when you press the home button, got an incoming call, etc. Place a call to the dispose method here.
  3. Put the call to the Gdx.app.exit() for example in the listener body of a button that's responsible for quitting the game, or catch the hit of the back button in Android and use it there.

This way you'll make sure all your resources are disposed of correctly and that you are not attempting to dispose of something for a second time.

Hope this helps.

\$\endgroup\$
0
\$\begingroup\$

Yes you can write your all code of your dispose in hide method. But if the problem still occurs then you can do your all dispose work just before when you load your Assets and make the SpriteBatch null at the starting and then make its object.

Like :

AssetLoader.dispose(); AssetLoader.load("path of texture","Type.class");

and

spriteBatch=null; spriteBatch=new SpriteBatch();

\$\endgroup\$
0
\$\begingroup\$

This is an old topic, but I had the same problem and finally figured it out by using Gdx.app.log("note: ", "dispose called") LogCat prints in the dispose method of each screen. What actually happens is (on Android):

  1. Press the HOME button => the method pause() gets called.
  2. Restart application again and at restart the dispose method of the last screen gets called to refresh the screen. Normally there shouldn't be any problems here.

The problem arises (at least in my case) when I pressed the RETURN button and restarted the app again, resulting in a crash. Now, this happens:

  1. Press the RETURN button => this calls the main dispose() method, NOT the pause() method. Therefore, every resource gets disposed.
  2. Afterwards, when relaunching the app, it tries to dispose the last screen again to refresh, but that already got disposed by pressing the RETURN button. So here is the problem: the dispose method of the current screen gets called twice when pressing RETURN, resulting in the following error: java.lang.IllegalArgumentException: buffer not allocated with newUnsafeByteBuffer or already disposed.

I solved this problem by using a boolean to check if the current screen already got disposed. Below is an example (I use an abstract Screen class and a ScreenManager, that sets a new screen by calling the create method of a subclass):

public class MainScreen extends Screen {

    private boolean disposed;

    @Override
    public void create() {
        disposed = false;
        //rest of your code here
    }

    @Override
    public void dispose() {
        if (disposed == false) {
            //dispose your resources here
            disposed = true;
        }
    }
}

So after pressing RETURN, disposed will be set to true. When relaunching it will still be true, so the resources do not get disposed twice. Next the screen gets reset, automatically calling create so disposed = false

I hope this helps anyone with a similar problem in the future :)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Why not just use: if(!disposed)? \$\endgroup\$ Commented Dec 21, 2016 at 15:39
0
\$\begingroup\$

Calling the Gdx.app.exit function calls the dispose function from the main ApplicationListener of the game anyway. Calling the function inside of the dispose causes a recursion of the function as it will reach the Gdx.app.exit function inside of the dispose function it calls leading to an error as it tries to dispose something that has already been disposed.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .