I've got a simple native application for debugging,
only displaying a triangle slowly changing the color.
Now, when i press the home-button and put my app into background
and then start it again, it is completely restarted.
How can i resume the old state?
I already tried to do it like in the native-app-example with:
app->userdata = &my_state;
if (app->savedState != NULL)
my_state = *(State*)app->savedState;
and in handle_cmd with:
case APP_CMD_SAVE_STATE:
app->savedState = malloc(sizeof(State));
*((State*)app->savedState) = my_state;
app->savedStateSize = sizeof(State);
break;
where State is class with all things i want to save.
How could i do this?
Isn't necessary to be a class. It could be a struct (that in fact is the "same"). You have to have all your values that you'll need to restore the state of the app in that struct or class, and read from that place.
Reading some examples, you'll see that it's normal to put an engine in the app userData like:
app->userData = &engine;
and in that engine, to have the struct from State. From that way, you could save only what you need, and leave the other.
The important thing is to use always the values (like the colour of the triangle) from that save state, and restore with that code you write.
PD: For more complex things, when you use dynamic memory, you'll have to be more subtle saving data.
Related
Everytime the application loses focus (whether manually by hitting the menu button, or by going to idle ) an APP_CMD_SAVE_STATE command is sent.
In the example shown from the Android API documentation for native activity (https://developer.android.com/reference/android/app/NativeActivity.html) , when this particular command is sent they are saving some sort of "state" inside their android_app .
// (...)
switch (cmd) {
case APP_CMD_SAVE_STATE:
// The system has asked us to save our current state. Do so.
engine->app->savedState = malloc(sizeof(struct saved_state));
*((struct saved_state*)engine->app->savedState) = engine->state;
engine->app->savedStateSize = sizeof(struct saved_state);
break;
// (...)
If you look in their code, savedState is just a struct holding values. First I thought that we need to save every single value that matters for our app everytime we lose focus, because otherwise the values would all become corrupt or something like that (yeah scary!)
I run a simple test by removing the code snippet above, and fortunately nothing changed, the values of my struct stayed the same after regaining focus even without saving them.
So I was wondering what is the purpose of this command ? Is that something important to consider ?
The APP_CMD_SAVE_STATE command is sent when your app loses focus. The aim is to make it possible to not only suspend your app, but, if the system has to kill the app to get some resources (e.g. free RAM), the app can be restored seamlessly next time the user returns to it.
If you look in their code, savedState is just a struct holding values.
Yes, from the point of view of the Native Activity, it's just a struct. But this struct is passed to Android in ANativeActivity_onCreate() function that's called via JNI (and usually it's implemented in android_native_app_glue.c from the SDK, which you could alter or replace if you need). Thus, Android will take care of the data when managing apps.
I run a simple test by removing the code snippet above, and fortunately nothing changed, the values of my struct stayed the same after regaining focus even without saving them.
Your test was too soft :) Try opening the Recents screen and close your activity from there: tap the × button or Close All command. The effect will be to kill the app, and you should now find that your data have been wiped unless you use the save-restore mechanism.
What is the correct way to handle objects within Android (Java)?
What I mean is, lets say I have a Splashscreen class and then I create an object from this class. Something like:
SplashScreen mySplash = new SplashScreen();
I then, within my onCreate method, display this splashscreen, like so:
loading_dialog.setContentView(mySplash);
loading_dialog.show();
....within the splashscreen I have bitmaps that are created.
Once everything has loaded, I finally get rid of the splash screen like so:
loading_dialog.dismiss();
So, the splashscreen is no longer a requirement.
What is the correct way to proceed now with regards to handling this redundant object?
Should I be doing something like:
mySplash.myBitmap.recycle();
mySplash.myBitmap = null;
mySplash = null;
Or maybe just
mySplash = null;
If I do this, does it mean that everything within mySplash (Bitmaps etc) will also be set to null?
Just not sure which of the above is required, or indeed, if neither is a good idea. Currently, I'm not doing anything, which I'm sure isn't right.
Also, and this is related, what happens if I also want to display this splashscreen if the user presses 'home' and then re-launches the app? If I've gotten rid of it, then I'm in trouble.
Glad for any advise.
I'm working in an Android game using libGDX framework while a learn from their wiki and Learning Libgdx Game Development book. The author of the book defines an Assets class to load game assets using an AssetManager. Every time the game is resumed the assets need to be reloaded so he use a call to Assets.intance.init(new AssetManager()) what reload the assets and create new objects to store textures references.
When I do this in my game, after resume, all I have are black boxes where I had nice textures so I suppose that the problem here is that I'm using the old references. I put here part of the code from the book:
AssetManager#init
public void init(AssetManager assetManager) {
/* Dispose previous asset manager */
if (this.assetManager != null) {
this.assetManager.dispose();
}
this.assetManager = assetManager;
assetManager.setErrorListener(this);
assetManager.load(Constants.TEXTURE_ATLAS, TextureAtlas.class);
/* Start loading assets and wait until finished */
assetManager.finishLoading();
Array<String> assetNames = assetManager.getAssetNames();
Gdx.app.debug(TAG, "Assets loaded: " + assetNames.size);
for (String assetName : assetNames) {
Gdx.app.debug(TAG, "Asset: " + assetName);
}
TextureAtlas atlas = assetManager.get(Constants.TEXTURE_ATLAS);
/* Create game resource objects. Here I get what I need from the atlas */
player = new AssetPlayer(atlas);
enemy = new AssetEnemy(atlas);
}
When I create my game objets I use Assets.instance.player and Assets.instance.enemy to store a reference to textures as the author of the book does so this could be the problem. The thing is that aftere re-read the book, I don't see how he solve this problem.
I'm pretty sure that I can solve the problem changing references in my game objects but all is becoming so messy. My real question is, how should I manage game assets in my game? I've been searching a lot for game examples but most of them don't use an AssetManager but instead static variables to textures.
Should I keep references of textures in game objects? It is really necessary to reload assets on resume? How could I reload textures in my game objects when all the objects are inside a worldController that don't know when a game is being resumed?
You're doing it correctly, as far as I can tell, at this level. You really do need to reload the textures, as your OpenGL context was lost, and all "pointers" into OpenGL-internal state are stale.
As you point out, because your AssetManager.player property points to a new object, anything that cached an old pointer is stale after a restart, and that is probably the source of your problems. (Though its hard to say for certain.)
If you look at the Libgdx SuperJump demo, they also cache all their asset pointers in static fields, but notice that the render calls effectively look up the texture every call. See WorldRenderer.renderBob(). One alternative would be to do a pass over your objects after (re)-loading assets to have them "refresh" their pointers the assets they use.
Have you tried not to call Assets.intance.init(new AssetManager()) on resume method (and also not to call Assets.intance.dispose() on pause method)?
Please read this link:
https://github.com/libgdx/libgdx/wiki/Managing-your-assets
At the end (Resuming with a Loading Screen) it says:
On Android your app can be paused and resumed. Managed OpenGL resources like Textures
need to be reloaded in that case, which can take a bit of time. If you want to
display a loading screen on resume, you can do the following after you created your
AssetManager.
Texture.setAssetManager(manager);
In your ApplicationListener.resume() method you can then switch to your loading screen and call AssetManager.update() again until everything is back to normal.
If you don't set the AssetManager as shown in the last snippet, the usual managed texture mechanism will kick in, so you don't have to worry about anything.
So, I believe that the author's approach is no longer necessary.
You only need to call Assets.intance.dispose() on dispose method in your "Game" class (I mean, the class that implements ApplicationListener).
Things were going well until I switched off the screen lock on my device, then things started going wrong intermittently.
I've managed to track the issue down and have some workarounds in mind BUT I would like to know if there is 'best practice' for avoiding or removing the issue.
The issue:
I have an application which changes images based on the application status.
The images are not huge but quite large (231k~) and are stored as resources.
After several screen rotations (I counted 27 with a project using a single ImageView), loading the images fails with Exception of type 'Java.Lang.OutOfMemoryError'
Stripped down to the barest project, the following demonstrates the problem:
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
//get a reference to the ImageView
var imageView = FindViewById<ImageView>(Resource.Id.imageView1);
imageView.SetImageBitmap( Android.Graphics.BitmapFactory.DecodeResource( this.Resources, Resource.Drawable.Ready) );
}
The above code is the only method I used to reproduce the issue.
Whilst attempting to resolve, I extended the example so that imageView was released in OnDestry:
protected override void OnDestroy ()
{
base.OnDestroy ();
imageView.SetImageBitmap( null );
imageView.DestroyDrawingCache();
imageView.Dispose();
}
This made no difference unless I added GC.Collect() which I don't want to do.
The best workaround I've currently thought of so far would be to modify the code as follows:
static Bitmap _ready = null;
private Bitmap GetReadyImage {
get {
if (_ready == null) {
_ready = Android.Graphics.BitmapFactory.DecodeResource (this.Resources, Resource.Drawable.Ready);
}
return _ready;
}
}
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
//get a reference to the ImageView
imageView = FindViewById<ImageView>(Resource.Id.imageView1);
imageView.SetImageBitmap( GetReadyImage );
}
This relies upon a static reference to each Bitmap and a property accessor for each.
I could even write a method which stores the images in a static List to save writing property accessors for each different property/variable.
I could perhaps add the flags ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize |ConfigChanges.KeyboardHidden) but this would break the normal Activity lifecycle which I've read isn't best practice?
I find it strange that having scoured the web, I've not yest encountered similar issues or examples. I'm left wondering how most others deal with this?
Any thoughts or comments are much appreciated.
I can only approach this problem from a truly native perspective, as I have not worked directly with the Mono framework.
The described symptoms are 100% indicative of a memory leak in the Activity, but the code shows no real evidence. If you can truly produce the issue with a project containing only one Activity and those four lines of code, it sounds to me like it is perhaps a framework bug that ought to be filed with Xamarin. Have you attempted to create the same simple project in pure Java to see how the results fare on the same device/emulator you are using? It would also be interesting to know if the issue is localized to a specific version of Android. I have never seen this particular behavior before in a native application project.
The awkward part is your statement that forcing a garbage collection makes the problem go away. You're right, you shouldn't have to do that, but a true memory leak (i.e. an unreleased reference) would still persist even if you hit the GC several times. The Android paradigm of destroying and re-creating the Activity on each rotation is such that even if the old Activity lived for awhile, when memory was tight it (and all its references) would quickly be collected to make room for a new instance. If this is not happening, and each Activity is living on past even the system triggered GC passes, perhaps there is a stuck reference in the native code generated by Mono.
Interestingly enough, technically your workaround actually does introduce a true leak, by attaching the Bitmap to a static field that is never cleared. However, I agree that in comparison it seems like a more efficient move. A simpler workaround might also be to code your Activity to manually handle configuration changes (I don't know if Mono is different, but this is accomplished by adding android:configChanges="orientation" to the manifest file). This will keep your Activity from being recreated on each rotation, but it may also require you to reload your view hierarchy if you have different layouts for landscape and portrait. However, even if you have to do this the Acitivity instance will be the same you can safely save the Bitmap without resorting to a static field.
However, if you cannot reproduce the problem with the same project in a native Java project, I would report a Mono bug.
Hard to see without the entire code but it obviously sounds like you have a memory leak. Screen rotation (due to the destroying/creation of the activity) is known to cause these. You might want to have a read at this article by Romain Guy as well as this talk from last year's IO.
I've got a small android application that implements the Observer pattern.
I want my "subject" (or the thing being observed) to change its state, such as changing its String from hello to hello world.
How can I do this via the emulator?
I need my (observing) android application to still run in the foreground so it can display whatever is being observed, but I need to find some way to alter the state of the observed object, is it possible to do this via the command line? How else can I "poke" the observed object to change its state.
One dirty-hack method I can think of is to set the observed object up in a loop, so every 10 seconds it changes its state, but that is not good as then I won't have control over it.
Correct answer: write a test case, and have the test case "poke" the observed object.
Not-quite-as-correct answer: add stuff to your activity to "poke" the observed object.