Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're 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

Posts I've Made

In Topic: Problem with loading bitmaps into Android Application

06 February 2012 - 08:55 AM

No worries at all, glad you got it working.

So longs the heap increases in size you will be fine (it may report 1% memory free and then up the heap size). Your issue was coming from the memory usage being at 48Megs and the virtual machine being unable to up the heap size any further. If you have it loading the bitmaps you need on a per level basis I doubt you will get anywhere near the 48Meg limit :).

I'd give it a try on various devices though just to be absolutely certain, but it does sound like you have solved your problem, well done.

In Topic: Problem with loading bitmaps into Android Application

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.

In Topic: How to pass context into onDrawFrame

02 February 2012 - 02:49 AM

I wouldn't pass the context into onDrawFrame. You won't be able to anyway if you are using the GLRenderer approach. It provides the method onDrawFrame(GL10 gl) and you are expected to just do your rendering there.

The context can be passed to the Renderer much like you have done via the constructor (this is ok) as you will need it, like you have correctly pointed out, to load resources and such like. The important thing is not to leak it. The context will come from the overarching activity that is currently active. It will be freed eventually assuming you didn't leak it when the activity is finished()

We used a TextureManager class to handle allocating the bitmaps and keeping track of what is loaded. You can make these bitmaps Weak or Soft references if you want to be really aggressive about how the Garbage Collector deals with them Posted Image (We did at one point, but no longer do...although we might change it back). We used the TextureManager so we could track what resources were being loaded and handle clearing them up again (If you do this you can log exactly what is going on a little bit easier and track down leaks). When you are done with a bitmap ideally you want to call recycle() on it then let the Garbage Collector do its thing. Whenever a game object needs a bitmap it just queries the TextureManager for it which _can_ load it on demand if needed or tell us that we have not actually allocated it or that we ask it to be allocated but it is now null (generally an indication that the Garbage Collector has eaten it ...which can happen as if no game objects are referencing it and the garbage collector runs it is likely the bitmap will be collected).

Some extra information on how we structured things (not even sure it is the correct way to do things but it works for us) and might give you some insight. We actually use the Canvas and the GlCanvas and use the onDrawFrame(Canvas) or onDrawFrame(GL10) of the Renderer to run our game loop. Essentially constantly having the renderer updating and delegating the drawing into the Canvas or GL context to an object such as a Scene (Which could be a level or just an animated menu etc). So all our onDrawFrame does is a standard game Loop. By adopting the same interface switching between OpenGL and standard Canvas is not a huge problem (Obviously the way you deal with textures and bitmaps between them differs a bit but our abstractions and TextureManager help us with that).

In Topic: Problem with loading bitmaps into Android Application

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

In Topic: Problem with loading bitmaps into Android Application

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