views:

47

answers:

2

All,

I'm aware that by default an activity will be killed and restarted when the screen orientation changes, or a keyboard is slid in or out. (See http://stackoverflow.com/questions/456211/activity-restart-on-rotation-android). My question is, what is the correct way to handle this from a Native code perspective? e.g. if I have a static block loading a native library and my app is restarted, how do I ensure that any memory in the native land is dealt with appropriately? The problem is

When we rotate the device, it looks like a separate Thread pool is created and the old ones are never removed. This means that every time someone turns the device, we have a ton more threads sitting idle and taking up memory

How do I ensure that this doesn't happen? I see from the JNIExample page some notes at the bottom:

[*]Unresolved issues and bugs Even though the example is fully functional, there are a couple unresolved issues remaining, which I was not able to figure out so far. Problems appear when you start the activity, then press the Back button to hide it, and then start it again. In my experience, calls to native functions in such restarted activity will fail spectacularly. callVoid() simply crashes with a segmentation fault, while calls to getNewData() and getDataString() cause JVM to abort with an error, because it is no longer happy with the globally cached object reference. It appears that activity restart somehow invalidates our cached object references, even though they are protected with NewGlobalRef(), and the activity is running within the original JVM (activity restart does not mean that JVM itself is restarted). I don't have a good explanation on why that happens, so if you have any ideas, please let me know.

Has this been solved?

A: 

If the VM is restarted, you start from scratch. If not, the state is right where you left it. There is no invalidation of cached object references that yanks things out from under NewGlobalRef. I wrote a few other notes about the wooyd article on the NDK mailing list.

If you have data that needs to be initialized when your activity is restarted, you should add an explicit initialization call to your activity (in onCreate, I think). Make sure you properly discard any stuff you retained from the previous round -- DeleteLocalRef then store NULL, don't just memset() to zero.

fadden
+2  A: 

Restarting in Android NDK is annoying. Any static data you have sticks around, because it reuses the process, so you need to manually reset anything that will be invalid on a new run (like any OpenGL texture or vertex buffer objects). It gives you a new Java thread and new Java Application and other objects as well, so any cached global references to objects that would be new in a new instance of your app need to be cleared as well.

So the strategy I use is twofold: Minimize restarts, and nuke everything on restart.

You minimize restarts by handling the configChanges in-app, as it says in the answer to the question you linked. Then opening a keyboard or rotating don't cause an app restart, which is as it should be for any app with non-trivial start up times.

And when I detect that a new instance of my app has started, I release everything critical from the old instance at that point, including releasing any Java objects I held onto via NewGlobalRef. I tried to minimize static data, but the few unavoidable places where I do keep around static objects I clear them when I detect the new instance starting up.

The old threads should go away once there are no more outstanding references to them (i.e., once you've released all of your NewGlobalRef objects).

SomeCallMeTim