--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.
It sounds OK to me. See ndk/docs/NATIVE-ACTIVITY.HTML for an alternative,
although your method is correct IMO if you have a normal Java activity.
> 2) Since I'm caching the reference to an _instance_ (the MainActivity
> actually), I'm wondering if JNI_OnLoad will be called when this
> instance is recreated? (my testing shows that if I exit the app and
> then reenter it, the references are still valid and native library
> still works as expected)
No, JNI_OnLoad is only called when the process which loads the library, and
hosts the Activity, is created. But a new process is not created whenever an
Activity in created. An app usually runs in a single process, which can stay
around for quite a long time, and within which activities can be created and
destroyed several times.
If your activity is only paused and resumed, then yes your activity reference is
still valid. This for example (usually) happens when the user presses Home and
then come back in your app. But if the user exits by pressing Back, then the
Activity will be destroyed, and you shouldn't hold a global reference to it in
your native code or you'll end up leaking memory, and will have certainly other
problems when working with this "zombified" activity.
> 3) I'm creating strings via env->NewStringUTF and passing them on to
> Java world. Who will free them? GC?
Yes
> 4) When should (MUST?) I call DeleteGlobalRef? Is there an
> JNI_OnUnload equivalent to JNI_OnLoad available?
There apparently is a JNI_OnUnload available:
http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#JNI_OnUnload
But I think you are still confusing process and activity lifecycle here. You
should delete the global references from onPause() or onDestroy().
That said, I hope that you're not relying on static variables in native code,
especially to hold your global references... Weird things may happen if you do
that. In my experience and opinion it's better to avoid any kind of native
static variable.
> 5) static functions don't work: I'm getting: No implementation found
> for native ... error message. I declared the function static and also
> the declaration in corresponding Java file. If I remove static,
> everything works. The reason I wanted to use static is beacuse of a
> JNI tip that "You should declare the methods "static" so the names
> don't take up space in the symbol table on the device." I am not
> explicitly registering functions though... (maybe autodiscovery
> doesn't find static methods?)
static in native code and static in Java are different things. Do not declare
the function static in C or C++, otherwise it is not available for dynamic linking.
>
> 6) Given that much of the codebase I'm integrating is in c++, does it
> make sense to develop activities in the NDK as well? Perhaps that
> would be easier because I wouldn't have to call java methods all the
> time to update the UI?
If you use the standard UI API, then you have no choice but to call Java methods
(from Java or from native code through JNI). What you could do is develop the
Controller part in native code, but you'll still have to use the Java API for
the View.
> 7) Probably a silly question, but I'm having hard time figuring out
> the whole C/C++ API that is available (I have yet to setup eclipse for
> C++ dev). What are you guys using as a reference to a C/C++ API that
> is available on Android? Currently, I'm between grepping the NDK
> header files and googling for method signatures... Is there such a
> thing as a compelte Bionic reference?
I grep too, and sometimes take a look at ndk/docs/STABLE-APIS.html
--
Olivier
I was writing my answer and didn't see yours ;)
On 06/13/2011 07:18 PM, Tim Mensch wrote:
>> 4) When should (MUST?) I call DeleteGlobalRef? Is there an
>> JNI_OnUnload equivalent to JNI_OnLoad available?
>
> You really should call it if a new instance of the Java Application is
> created, with any global objects from the old instance. You could hold
> on to anything that you're SURE doesn't have a reference to an
> Application, an Activity, or a View-derived class.
>
> I'd say that you should call it in onDestroy(), but don't. onDestroy()
> has a bad habit of being called AFTER the onCreate() of the new
> instance, so there's no point in actually doing any destruction there if
> you've got statics in your JNI code. Just release everything when a new
> instance is created.
Yes, I've seen the same thing, onDestroy() being called after onCreate(), and
similar things with onPause() and onResume(). What this means is that several
instances of the same activity can "live" at the same time, and this can result
in bad problems with static variables in native code.
I personally use absolutely no native static variable, and rely on native
objects for encapsulation: I keep native pointers as Java long values in Java
wrappers. This way, several activities can live at the same time, it's safe.
IMO native statics are quite bad in general, and pure evil on Android, because
of the distinction between Activities/Services/etc.. and processes.
--
Olivier
I understand. Actually, I'm very strict on OO encapsulation, and I especially
like to do that in pure C :)
> Yes, I could do that, and it wouldn't be the end of the world, but I
> don't actually see enough of an advantage. Given that you can't play
> more than one copy of a game at a time, I find it's a reasonable
> trade-off to just give up on "pure OO" cleanliness in exchange for API
> cleanliness. Sure, if I wanted to have several copies of the game
> running in the same context, I might have issues -- but I don't think
> I've ever actually needed to do that in reality, and so I'm not highly
> motivated to make sure the design handles a feature I've never used. ;)
In your case you "can't play more than one copy of a game at a time", ok. But I
think it's dangerous to extrapolate this to: anyway there's always one activity
running at one time.
Especially, if one tries to optimize an app for tablets using the new Fragments
API, what was activities may become parts of the UI. And proper encapsulation in
the design may be critical for this. And who knows what API/platform/spaceship
will come next? That's the thing with clean designs, it /helps/ to anticipate.
> I guess I've gotten cynical in my old age: If I don't see an immediate
> benefit from adding typing to my daily coding, then I don't want to add
> that typing, even if it satisfies some criteria of cleanliness -- I've
> been there and done that, and now the pendulum is swinging back toward
> "do the minimal I need to ship the game."
Well, I take some shortcuts too.. It depends on the goal.
The one thing is that I'm generally working on software which is meant to grow
slowly, evolve regularly, on a long term basis. I need as much maintainability
as possible. And such software or some /modules/ are often candidates for being
ported or reused. So it has be clean, modular and sort of abstract.
Anyway, I consider game development to be a true specialty, and I know near to
nothing about it. It's very different from audio software, which I focus on. In
my case, a little design mistake can become a big problem on the long run. And
well, it does. That said, the OP doesn't seem to mention a game.
> Also, I use enough memory that if a full second instance of a game
> really did load, it would be (at least temporarily) twice the size with
> no real benefit, and you'd need to reload assets that were already in
> memory -- so it seems objectively useful to keep your asset management
> in static, persistent structures, that would even be useful across
> global context instances, if you choose to implement them.
Memory's a pretty valid argument IMO. I would maybe look for other solutions to
respect OO encapsulation, but I understand the need to break certain rules when
working in an embedded environment. I somehow do that too with other things, and
it's absolutely required in my case on Android for performance reasons.
> And finally, if you're porting someone else's game, you simply don't
> have a choice in the matter.
Sure, alchemy's not an option yet :)
--
Olivier
Tim
> With regards to statics at all: I do need a way to call to java from a
> different thread; so I need to have a reference somewhere. And global
> reference is the only thing that works (I've tried passing a local
> reference to a thread method, but all I got was invalid pointers).
I am not questioning the need for global references. You need that.
Also, I think I/we have introduced a bit of confusion, the problem isn't
strictly with /static/ variables but with global variables in native code.
JNI global references and global variables in C/C++ code are two distinct
things. You can keep a global reference in a C++ class member, in a C struct,
etc... I personally recommend that you follow OO principles, and avoid global
variables, especially for storing JNI global references.
> If I understood you correctly (Oliver), it is possible that when the
> use reenters the app, a NEW activity will be created, but the native
> library will be the same (because it is statically loaded)? And since
> library would be hanging on to a reference to the old activity, that
> would prevent it from being garbace collected, hence using memory. But
> if I was to release it in this case, it would be OK, right?
Yes you understand correctly what I meant. But the subtlety is that instance A
of an activity may be destroyed AFTER instance B of the same activity is
created. So, if your JNI global reference is stored in a native global variable,
and that you delete the JNI global reference from onDestroy(), you may both leak
the old activity, and delete the new activity reference right after creating it.
This is why Tim advises not to delete the reference in onDestroy(), but in
onCreate(), where you can test if the native global variable is already set, and
delete the reference if needed, just before you create a new reference.
As I said, I don't like this approach for several reasons. One reason is that it
uses memory while the app is idle. When the activity is destroyed it can not be
garbage collected until the user comes back to the app.
So you could use a weak reference for that, but I personally find this a bit
dangerous unless you really know what you are doing.
> I think I'll try to release it on onPause (I'll try to end all
> activities then) and reconnect it on onResume or onCreate. That's
> probably safest and would allow GC to collect the activity when the
> user is not running it (the app).
That could work.
> Oliver, you also write: "That said, I hope that you're not relying on
> static variables in native code,
> especially to hold your global references..."
>
> But there is a specific guidance on that in JNI tips that in order to
> do lookups, etc, one should create a global reference. How can I call
> from a native thread to the java world if I don't cache a reference?
Of course, you need to cache the global reference. After all, that's what global
references are usually meant for, being cached. I just warn you about global
variables. And avoiding these is rather easy, by following simple OO and
callback patterns.
For example, in onResume(), you can pass an object which implements a listener
interface to your native code and bind it to a callback. Then, in onPause(),
simply clear the callback and delete the global reference to the object. All
this can be achieved with native structs/classes, without the need for a single
global or static variable. This way, each activity instance operates in a well
encapsulated scope, and you don't need to care about conflicts at global scope.
--
Olivier