Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Fiallen

Member Since 13 Sep 2011
Offline Last Active Feb 06 2013 10:05 AM

#4909154 Problem with loading bitmaps into Android Application

Posted by Fiallen on 03 February 2012 - 07:52 AM

In fact, I am trying to load all the bitmaps which I need for the whole game. I don't think this is the right thing to do, I would much more prefer to load only the bitmaps which I need for the first level, and load bitmaps for another level as and when I start that particular level, but I don't know how to do it either - to load the bitmaps later, I need the Context and I don't know how to pass it into onDrawFrame function, where is my main game loop (as explained in my other post http://www.gamedev.n...__fromsearch__1)


Ahhh Posted Image yes. Don't do that, I assumed you would be loading only the stuff you needed. You want to load your resources as you need them (As you have correctly pointed out). So if your level needs 10 textures load 10 textures. I have posted some information on your other thread.

You don't want to pass the context to onDrawFrame the interface won't let you. What you can do is pass the context into the Renderer so that it is available for use elsewhere.

This might get a bit long and so I apologise if i am being too verbose and at too simple a level. Also I am not making any claims that this is the only way to do things.

You have your Activity (Generally you will have an activity for the game, and 1 or more activities for menu screens and so forth). Moving between your activities is a place where you can decide to do some loading of the things you need for the next activity and free up any memory (If this is going to be a time consuming process you display a lightweight loading screen while the loading takes place).

In your activity for your game I am assuming you will have your GlSurfaceView and your GlRenderer of some kind. The surface view as far as I recall has a setRenderer method that allows you to inject the renderer you want to use. The GlRenderer exposes the onDrawFrame(GL10 gl) method which will get called constantly by the surfaceView. It sounds like your onDrawFrame(GL10 gl) looks a little like the below.

public void onDrawFrame(GL10 gl) {
	 endTime   = System.currentTimeMillis();

	 long  dt  = endTime - startTime;
	 int   fps = Math.round(1000f / dt);
	
	 if (fps < TargetFps) {
		  try {
			   Thread.sleep(TargetFps - fps);
	 	 } catch (InterruptedException e) {}
	 }
	
	 startTime = System.currentTimeMillis();

	 // update the game state
	 // render the game using the gl context  
}

So your question is how do I get my Bitmaps into memory such that my Level has access to them?

I would very much recommend using a class purely for loading the bitmaps (This can be a Singleton but you have to be careful about how you work with a Singleton in Android as your application can be killed at anytime and thus your Singleton has to rebuild its state when the app resumes. For managers of things like bitmaps and sounds this generally is not a big deal and easily handled.).

You could possibly do something like the below if you use a singleton style object for handling your bitmap management.

// This is just off the cuff code, i don't expect it to compile it's just to give you an idea.
public class GameActivity extends Activity {
	 @Override
	 public void onCreate(Bundle savedInstanceState) {
	 	 super.onCreate(savedInstanceState);
		  MyGameLevel level = createTheLevel();
				  
		  GlSurfaceView view = // Get a hold of your view or create it
		  Renderer r = new LevelRenderer(level);
		  view.setRenderer(r);
				  
	 	 // If this causes noticeable issues on starting the activity don't do it
	 	 Runtime.getRuntime().gc();
	 }
	  
	 private MyGameLevel createTheLevel() {
	 	 // Create a level it can load the textures
	 	 MyGameLevel level = new MyGameLevel();
	
	 	 // Load all the textures i need (this could be done by the level class this is just an example for arguments sake)
	 	 MyTextureManager.instance().loadBitmap(context, R.drawable.whatever);
	 	 MySoundManager.instance().loadSound(context, R.raw.sound1);
	
	 	 // etc...but all your resources are loaded
	 }
}

public class LevelRenderer extends Renderer {
	 MyGameLevel level;

	 public LevelRenderer(MyGameLevel l) {
	 	 level = l;
	 }

	 @Override
	 public void onDrawFrame(GL10 gl) {
	 	 // Game loop
		  level.update(dt);
		  level.render(gl);
	 }

	 @Override
	 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
	 	 // You can do this or you can wait until you call level.render before binding the textures, your implementation will suit your needs
		  level.bindGlTextures(gl, config);
	 }
}

public class MyGameLevel() {
	 public void bindGlTextures(Gl10 gl, EGLConfig config) {
	 	 // here you can use the MyTextureManager to get the bitmaps and bind them to your gl context as you call this as soon as the surface is
	 	 // created...if you wan't to, delay this until the render call it is fine the important thing is the Textures exist already in the manager in bitmap form.
		  // something like ....can't quite remember the syntax
		  gl.bindTexture(GL_TEXTURE_2D, MyTextureManager.instance().getBitmap(R.drawable.whatever);  
	 }

	 public void render(GL10 gl) { // draw the level }

	 public void update(long dt) { // update the level }
}

There are many ways to achieve the same thing so what I have posted above is one method for loading the Bitmaps and providing access to them. In the onfinish method of the activity you can clear the texture manager and recycle any bitmaps you no longer need. Does this help at all?

I realised I didn't post any code for the MyTextureManager class I made up in the example above...however I think you can get the idea. You are just using that as a cache to store your Bitmaps. The method to load a bitmap takes the context which is readily available in the Activity (where I used it in my example..but it can be wherever you pass the context...you could for example call getApplicationContext() in your Activity and pass that context into the Level and have the Level manage putting the Bitmaps it needs into the MyTextureManager) and a resource ID. Thus you would just call BitmapFactory.decodeResource(context.getResources(), resourceId). Obviously how you architect things will be suited to your needs I am just proposing ideas to get you thinking.


#4908651 Problem with loading bitmaps into Android Application

Posted by Fiallen on 02 February 2012 - 02:14 AM

It certainly could be related to your problem as you are doing quite a few allocations very quickly and are running dangerously close to the limit :) (I don't think we come anywhere near that in terms of memory usage).

Certainly the Garbage collector is doing the correct thing before your OOM and having one last shot at freeing stuff up. If you are leaking memory (holding onto it for longer than you intended) then this might be an issue (particularly as you are so close to the 48MB limit). You will see times where things work fine and then others where the Garbage Collector is unable to collect something you thought should be freed up and just can't collect enough to carry on (We saw something similar flicking back and forwards on our menu screens as they had large backgrounds and we leaked some memory each time). Does anything happen in your game before this loading of the images? (A menu system, other activities as leaking the context is quite common).

Was there anything particularly different in the scenes for the log where you have the successful result and the crash? or were they exactly the same test? (Was it running on the phone or the emulator?). It looks like a pre load of all the resources before starting a level (which is definately the right thing to do).

Given you are so close to the 48MB limit you might want to look into how your resources (pngs, oggs so on and so forth) are setup (I can't comment on this as I don't know much about your project but I know I had to drag our artists back into the real world of having to be as conservative as they could).

I will post an answer on your other post just now which might clear things up a bit in terms of how to structure your code (not that I am an expert by any stretch of the imagination).


#4908316 Problem with loading bitmaps into Android Application

Posted by Fiallen on 01 February 2012 - 03:03 AM

Are you using LogCat to track the exact nature of the exception and get the stack trace? (It's sometimes not the easiest thing to read but with the latest ADT for Eclipse it is much easier to filter).

When I was seeing our OOM exception LogCat was able to tell me the resource Id i was loading and how much memory it was trying to allocate (With the stack trace it was more than enough to diagnose the cause)? It might be helpful if you post that up (when i saw we were allocating 10 megs just to draw 1 background I knew exactly what was up and resolving it was not an issue).

You are more than likely already aware that the .png's are small in their compressed state but once loaded into memory they are uncompressed bitmaps so will consume (width x height x bytesperpixel) bytes. It is also extremely easy to leak memory in Android but I don't believe this is your issue from your original post.

We had a few issues with the memory management on Android initially but once we refactored our engine to be a bit more Android friendly we were fine.


PARTNERS