[*]Java interface
We start by defining a Java classJNIExampleInterface,   which will provide the interface to calling the native functions, defined in a   native (C++) library. The native functions corresponding to Java functions will   need to have matching call signatures (i.e. the count and types of the   arguments, as well as return type). The easiest way to get the correct function   signatures in the native library is to first write down their Java prototypes, and then   use the javah tool to generate the native JNI header   with native function prototypes. These can be cut and pasted into the C++ file   for implementation.  The   Java functions which are backed by the corresponding native functions are   declared in a usual way, adding a native qualifier. We also want to demonstrate   how we could do the callbacks, i.e. calling the Java code from native code. That   leads to the following high-level view of our interface class:
<JNIExampleInterface.java>= package org.wooyd.android.JNIExample; import android.os.Handler; import android.os.Bundle; import android.os.Message; import org.wooyd.android.JNIExample.Data; public class JNIExampleInterface { static Handler h; <Example constructors> <Example native functions> <Example callback> }
One   valid question about this definition is why we need a Handler class attribute. It turns out that it   will come in handy in situations, when the native library wants to pass some   information to the Java process through a callback. If the callback will be   called by a native thread (for extended discussion see "Calling Java functions"   section [->]), and then   will try to modify the application's user interface (UI) in any way, an   exception will be thrown, as Android only allows the thread which created the UI (the UI   thread) to modify it. To   overcome this problem we are going to use the message-passing interface provided   by Handler to dispatch the data received by a   callback to the UI thread, and allow it to do the UI modifications. In order for   this to work, we are going to accept a Handler instance as an argument for non-trivial   constructor (reasons for keeping trivial one will become apparent later), and   save it in a class attribute, and that's pretty much the only task for the   constructor:
<Example constructors>= (<-U) public JNIExampleInterface() {} public JNIExampleInterface(Handler h) { this.h = h; }
To illustrate various argument-passing techniques, we define three native functions:
- callVoid(): takes no arguments and returns nothing;
- getNewData(): takes two arguments and constructs a new class instance using them;
- getDataString(): extracts a value from an object, which is passed as an argument.
<Example native functions>= (<-U) public static native void callVoid(); public static native Data getNewData(int i, String s); public static native String getDataString(Data d);
The callback will receive a string as an argument, and dispatch   it to the Handler instance recorded in the constructor,   after wrapping it in a Bundle:
<Example callback>= (<-U) public static void callBack(String s) { Bundle b = new Bundle(); b.putString("callback_string", s); Message m = Message.obtain(); m.setData(b); m.setTarget(h); m.sendToTarget(); }
We also need a definition of a dummy Data class, used purely for illustrative   purposes:
<Data.java>= package org.wooyd.android.JNIExample; public class Data { public int i; public String s; public Data() {} public Data(int i, String s) { this.i = i; this.s = s; } }
After   the source files Data.java and JNIExampleInterface.java are compiled, we can generate the JNI   header file, containing the prototypes of the native functions, corresponding to   their Java counterparts:
$ javac -classpath /path/to/sdk/android.jar \ org/wooyd/android/JNIExample/*.java $ javah -classpath . org.wooyd.android.JNIExample.JNIExampleInterface
Native library implementation
At a high level, the Java library (consisting, in this case, of a single source fileJNIExample.cpp)   will look like that:  <JNIExample.cpp>= <JNI includes> <Miscellaneous includes> <Global variables> #ifdef __cplusplus extern "C" {
 
0 件のコメント:
コメントを投稿