Game Development Reference
In-Depth Information
Creating Java Native Methods
As we saw previously, it's rather simple to specify which methods of a Java class are
implemented in native code. However, we need to be careful when defining what types we pass
into the method and what return type we get out of the method.
While we can pass any Java type to a native method, some types are considerably harder to
handle than others. The easiest types to work with are primitive types like int , byte , boolean , C,
and so on, which correspond directly to the equivalent C types. The next easiest types to handle
on the C/C++ side are one-dimensional arrays of primitive types, such as int[] or float[] .
These arrays can be converted to C arrays or pointers with methods provided by the JNIEnv type
we saw earlier. Next on the easiness scale are direct ByteBuffer instances. As with arrays, they
can be easily converted to a pointer. Depending on the use case, strings can be easy to use as
well. Objects and multidimensional arrays are a lot harder to handle. Working with those on the
C/C++ side is similar to working with the reflection APIs on the Java side.
We can also return any Java type from native methods. Primitive types are again rather easy to
handle. Returning other types usually involves creating an instance of that type on the C/C++
side, which can be pretty complicated.
We'll only look into passing around primitive types, arrays, ByteBuffer instances, and strings
a little bit. If you want to know more about how to handle types via the JNI, we refer you to the
(online) book Java Native Interface 5.0 Specification , at http://docs.oracle.com/javase/1.5.0/
docs/guide/jni/spec/jniTOC.html .
For our JNI experiment, we'll create two methods. One will copy a float[] to a direct
ByteBuffer in C code, and the other will print out a string to LogCat. Listing 13-1 shows our
JniUtils class.
Listing 13-1. JniUtils.java; We Keep It Simple
package com.badlogic.androidgames.ndk;
import java.nio.ByteBuffer;
public class JniUtils {
static {
System.loadLibrary("jniutils");
}
public static native void log(String tag, String message);
public static native void copy(ByteBuffer dst, float[] src, int offset, int len);
}
The class starts with a static block. The code in this block will be invoked the first time the VM
encounters a reference to the JNIUtils class. It's the perfect place to call System.loadLibrary() ,
which will load the shared library we'll compile in a bit. The parameter we pass to the method
is the pure name of the shared library. As we'll see later, the actual file is called libjniutils.so .
The method will figure this out on its own.
 
Search WWH ::




Custom Search