Android NDK Development Chapter (v): Java and Native code communication (data manipulation)

Source: Internet
Author: User
Tags java reference

Although the use of the NDK can improve the efficiency of Android programs, it is a little cumbersome to call. The NDK is able to use Java's native data types directly, and reference types, because the Java reference type is now shielded from the actual ndk, so the NDK uses Java reference types to do the corresponding processing.


I. Operations on reference data types

Although the Java reference type's actual NDK is now masked, JNI provides a set of APIs that provide native method churn and reference types using Java through the JNIEnv interface pointers.

1. String manipulation

JNI treats Java strings as references and uses Java strings in the NDK, requiring the relevant APIs to be converted. JNI supports Unicode-encoded and UTF-8-encoded strings, and two sets of functions handle these string encodings through JNIEnv interface pointers:

Jstring javastring;javastring = (*env)->newstringutf (env, "Hello World");

The method generates a UTF-8 encoded string.


2. Java string to C string

To use a Java string in a native method, you need to convert the Java string to a C string. Ability to call the Getstringchars function:

Const Jbyte *str;jboolean iscopy;str = (*env)->getstringutfchars (env, javastring, &iscopy);

The third parameter, iscopy, can be used to infer whether the string returned by the function is a copy of the Java string, or the memory that points directly to the Java string.


3. Release the string

The C string obtained by the Getstringchars and Getstringutfchars functions called by JNIEnv is freed correctly after use, or a memory leak is caused. The string can be freed through the Releasestringutfchars function (for freeing Unicode) and the Releasestringutfchars function (for releasing UTF-8).

(*env)->releasestringutfchars (env, javastring, str);(*env)->releasestringchars (env, javastring, str);


Second, array operation

JNI treats an array of Java as a reference type, but JNI or provides a function to manipulate the Java array.

1. Creating an array

You can create an array instance directly with the New<type>array function. The type can be a native data type, or it can be an object, using the corresponding API to pass the parameters to determine the size.

Jintarray Array;array = (*env)->newintarray (env); if (0 = = array) {    //Do It}

2. Array of Access questions

JNI has two ways to access the Java array, the ability to copy the code of the array into a C array, and then manipulate the C array, and then commit the changes, so the efficiency is a bit low. Another option is to have JNI directly provide pointers to array elements.

Method One: Use copy, call get<type>arrayregion function copy, set<type>arrayregion function commit change

Copy the Java array to the C array jintarray javaarray;jint array[10];//...//copy Array (*env)->getintarrayregion (env, Javaarray, 0, 10, array);//Do it//commit changes (*env)->setintarrayregion (env, Javaarray, 0, array);

when the array is very large, the efficiency of this method is very low.


Method Two: Directly manipulate the pointer, call the Get<type>arrayelements function to get the pointer of the array


Jint *array;jboolean iscopy;jintarray javaarray;//... array = (*env)->getintarrayelements (env, Javaarray, & Iscopy);

the third parameter iscopy the function of the Java string to the C string, whether it is a copy of the Java array.

After use, it is necessary to release immediately, otherwise it will cause a memory leak, the release function is Release<type>arrayelements

(*env)->releaseintarrayelements (env, Javaarray, array, 0);

the third parameter, 0, represents copying the content back and releasing the native array. If it is jni_commit, it is copied back, but not released. Jni_abort, released but not copied back.


Iii. operation of NiO

JNI provides the NIO action function, which enables Java to use the buffer created by the native code. The NIO buffers are better at transmitting data than array operations, and are suitable for transferring large amounts of data between native code and Java applications.

1. Create a byte buffer, using the Newdirectbytebuffer method

unsigned char *buff = (unsigned char *) malloc (1024x768);//... jobject directbuff;directbuff = (*env)->newdirectbytebuffer (env, buffer, 1024);

It is important to note that the native method's memory allocation is not managed by the virtual machine, so it is necessary to manually manage the memory to avoid a memory leak.


2. Get the Java byte buffer

Java can also create byte buffers, calling the Getdirectbufferaddress function in the native method to get the memory address of the native byte array

unsigned char *buff;jbytearray directbuffer;//... buffer = (unsigned char *) (*ENV)->getdirectbufferaddress (env, Directbuffer);

Iv. Field of Access

The native method wants to get the member variables of Java and call the Java member functions by using the Access domain method provided by JNI.

Java has two domains, each of which is an instance domain and a static domain. The object of a class has a copy of its own instance domain, and all objects of a class share the same static domain. There are Java classes, Javaclass:

public class Javaclass {private String Instancefield = "instance filed";p rivate static string Staticfield = "static Filed" ;p rivate String Getinstancefield () {return instancefield;} private static String Getstaticfield () {return staticfield;}}


1. Get the domain ID

JNI provides access to two domains through the domain ID, the ability to get the class object through the instance, and then get the domain ID, using the Getobjectclass function to get the class object

Jclass clazz;jobject instance;//... clazz = (*env)->getobjectclass (env, instance);

depending on the type of domain, use the Getfieldid function to get the instance domain Id,getstaticfieldid get the static domain ID, the return type is Jfieldid;

Jfieldid fieldid;//Get instance domain Idfieldid = (*env)->getfieldid (env, Clazz, "Instancefield", "ljava/lang/string;"); /get static domain Idfieldid = (*env)->getstaticfieldid (env, Clazz, "Staticfield", "ljava/lang/string;");

The last parameter of the two function is the domain descriptive descriptor in Java that represents the domain type.

The ability to cache the most frequently used domain IDs can improve performance.


2. Get domain

Once the domain ID is obtained, it is possible to get the instance domain through the Get<type>field function and get the static domain through Getstatic<type>field

Jstring field;//Get instance domain field = (*env)->getobjectfield (env, instance, FieldID);//get static domain field = (*env) Getstaticobjectfield (env, Clazz, FieldID);

Getting the value of a Java domain calls two to three JNI functions, which is cumbersome and inefficient, and it is recommended to pass the required parameters to the native method, which improves performance.


Iv. Method of Invocation

1. Get the method ID

As with domains, there are two types of Java methods, access to these two types of methods, first to get the ID of the method, using Getmethodid and Getstaticmethodid, the return value type is jmethodid.

Jmethodid methodid;//Get instance method Idmethodid = (*env)->getmethodid (env, Clazz, "Getinstancefield", "() ljava/lang/string;"); /Get static method Idmethodid = (*env)->getstaticmethodid (env, Clazz, "Getstaticfield", "() ljava/lang/string;");

The last parameter representation of two methods describes the descriptor, which is represented in Java by the method signature.


2. Call method

The method is called by calling the Call<returntype>method and Callstatic<returntype>method functions with the method ID as the parameter.

Jstring result;//Call instance method result = (*env)->callstringmethod (env, instance, methodid);//Call static method result = (*env) Callstaticstringmethod (env, Clazz, Methodid);

the cost of converting Java methods to native code is relatively high, and it is recommended that you plan for the class design so that you have better performance.


V. Domain and method descriptive descriptors

Using the member variables and methods of Java, it is necessary to get the IDs of the fields and methods through the domain descriptive narrative notation and the method descriptive descriptor. The signature mapping relationships for Java types are as follows:

Boolean-Z

Byte-B

Char-C

Short S

Int-I

J, Long

Float-F

Double-D

Other Class-L + class name (package name separated by ' \ ')

type[]-[type

method, (parameter type signature) + return type signature


Visible use is quite troublesome.


With regard to the communication between Java and native code, assuming a memory leak occurs, the API returns NULL, and when the crash assumes that no exception is thrown, the native code will stop executing and the application will flash back.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.