05. NDK Integration (JNI)

  • Description: Integrating NDK into Android SDK apps, Standard JNI, Android JNI
  • Practical part: NDK Apps/libraries called from Java or Java called from C/C++
  • Semester project starts: select topic and start development

Lecture

Practical

Lab archive: lab-5.zip Lab solutions: lab-5-solved.zip

Resources

Task 0

Download the lab archive and import the project into Eclipse (New > Project and then Android > Android Project from existing code). Build and run the application. You will notice there are 8 buttons, each with a TextView associated. Each of them correspond to a task, in order.

Task 1 - Call a Java method from native code

For the first task you have to call the setText() method from native code. To do this, you have to call

env->CallVoidMethod(obj, mID);

where obj is the object you want to call the method on and mID is the method ID. The Void in the name suggests that the method returns void.

To get the method ID you have to call

jmethodID mID = env->GetMethodID(cls, "setText", "()V");

where cls is the class the method is part of, the first string is the method name and the second string is a method signature. In this case, the method takes no parameters ”()” and returns void “V”.

Finally, to get the class, call

jclass cls = env->FindClass("ndk/lab5/tasks/MainActivity");

which has a single parameter, the class name and package, with the path divided by ”/”.

It is good practice to check for null when getting a class or methodID, and treating the error as required.

Task 2 - Call a Java method with a parameter from native code

For the second task you have to call setText(String) method from native code. This is similar to the above task execept the method signature has changed, instead of ()V, the new method signature will be (Ljava/lang/String;)V. All parameters must have ; after them if they are objects. Objects are defined as L followed by the fully qualified class. Check the JNI Types Documentation.

To set the parameter, create a new jstring, and give it as a parameter after the methodID.

jstring str = env->NewStringUTF("OK");
env->CallVoidMethod(obj, mID, str);

Remember to release the string after you are done with it.

env->ReleaseStringUTFChars(str, env->GetStringUTFChars(str, NULL));

Task 3 - Get the return value of a Java method

Call String getInput(). This method returns the content of the EditText box under of task 3. There are three things that need to change from the first task: the method name, the method signature, which will now be ()Ljava/lang/String; and the method call itself, which should be

jstring str = (jstring) env->CallObjectMethod(obj, mID);

Now, call setText(String, int), giving it as parameters the int that task3 receives and the jstring obtained from getInput. There is an easy way to obtain the signature of a function by using javap. Call it like this:

javap -classpath $WORKSPACE/Lab5_Tasks/bin/classes/ -p -s ndk.lab5.tasks.MainActivity

javap is used to disassemble java files, and the -s parameter is used to generate the signatures for public functions and fields, -p tells it to also generate signatures for private members of the class. Remember to call ReleaseStringUTFChars after you are done with the string.

Task 4 - Call a static method

This time, you have to call the getInt method and then check the result with checkInt. These are static methods. Accessing static methods is very similar to accessing instance methods. There are two changes: instead of using GetMethodID, use GetStaticMethodID, and when calling the function use CallStatic<Type>Method, passing the class instead of an object as first parameter.

Task 5 - Get the value of a field

Get value of the field “field” and return it. Getting the value of field means calling

jint i = env->GetIntField(obj, fID);

where obj is the object and fID is a jfieldID containing the ID of the field. To get the field ID, you need the class, obtained like in the previous exercises and to call

jfieldID fID = env->GetFieldID(cls, "field", "I");

where, cls is the jclass, “field” is the field name and “I” is the signature. Field signatures can also be obtained with javap (or by checking the JNI Types Documentation).

Task 6 - Set the value of a field

Set the value of the field “field” with the value received as a parameter. Instead of calling GetIntField, you will have to call

env->SetIntField(obj, fID, i);

with i being the value you wish to set the field to.

Task 7 - Generate an exception

Generate an exception. To generate an exception you have to get the class of the exception and then call

env->ThrowNew(exception, "JNI Generated Exception");

where exception is the class of the exception. The string provides additional information.

Task 8 - Check for an exception

Call the generateException method and check if it generated an exception. Return JNI_TRUE if yes, and JNI_FALSE otherwise. To check for an exception you can either call

jboolean ex = env->ExceptionCheck();

which returns JNI_TRUE if an exception has occurred and JNI_FALSE otherwise or

jthrowable ex = env->ExceptionOccured();

and check if ex is null or not. Remember to clear exception status, otherwise it will be thrown back to the JVM when the function returns.

env->ExceptionClear();
ndk/courses/05.txt · Last modified: 2014/08/10 13:56 by petre.eftime
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0