Android uses JNI (calls local functions from java)
When compiling an application with a mixture of Local C code and Java, you need to use the Java Local interface (JNI) as the Connection Bridge. As a software layer and API, JNI allows you to use local code to call Java object methods, and also allows you to call local functions in Java methods.
On the Java end, developers only need to add the native keyword before connecting to the local function method. In this way, the VM will look for this local function.
1. Call Local functions from Java
When calling local functions from Java, You need to define a special method with the native keyword in the class to serve as a bridge to connect local code. Through this definition, JVM will find a local function with the package name, class name, and method name when calling a local method.
package com.example.liyuanjing.jniproject;import android.util.Log;public class NativeSorting { static { System.loadLibrary("sorting_jni"); } public NativeSorting() { } public void sortIntegers(int[] ints) { nativeSort(ints); for (int i = 0; i < ints.length-1; i++) { System.out.print(String.valueOf(ints[i])); Log.i("liyuanjinglyj",String.valueOf(ints[i])); } } private native void nativeSort(int[] ints);}
The above is a simplified example, including a method for sorting the int array. In addition to constructors, there are two methods. The first is sortIntegers (), which is a common Java method and can be called in other Java classes. The second is nativeSort (). This method points to the function in the local code. Although local methods can be defined as public, it is better to wrap them as private methods in a Java method for some error handling.
You can write local code from the beginning, but you can also use the javah tool to generate some code. This tool is in the Java SDK. It generates a C-Language header file, including the function definitions corresponding to the local method. First, compile the Java program code, and then run the following command in the src/main directory of the current project:
Javah-classpath.../../build/intermediates/classes/debug/-d jni/com. example. liyuanjing. jniproject. NativeSorting
The above command shows how to generate a header file for NativeSorting in the previous sample code. -The classpath parameter specifies the location of the compiled class file. Note that it is not a DEX file. The-d parameter specifies the output directory of the generated header file. After running the command, the com_example_liyuanjing_jniproject_NativeSorting.h file is generated in the jni Directory, which contains the definition of the local function.
/* DO NOT EDIT THIS FILE - it is machine generated */#include
/* Header for class com_example_liyuanjing_jniproject_NativeSorting */#ifndef _Included_com_example_liyuanjing_jniproject_NativeSorting#define _Included_com_example_liyuanjing_jniproject_NativeSorting#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_liyuanjing_jniproject_NativeSorting * Method: nativeSort * Signature: ([I)V */JNIEXPORT void JNICALL Java_com_example_liyuanjing_jniproject_NativeSorting_nativeSort (JNIEnv *, jobject, jintArray);#ifdef __cplusplus}#endif#endif
This code is the generated header file. As stated in the first line, do not modify this file. All developers need to do is copy the function definition to the. c file that implements the function.
The following code demonstrates the implementation of the jni function in the header file com_example_liyuanjing_jniproject_NativeSorting.h. In this example, the JNI_OnLoad function does not perform many operations, but returns a constant representing the current JNI version 1.6, this is a version supported by Dalvik VM. The following is array. c code:
#include
#include #include "com_example_liyuanjing_jniproject_NativeSorting.h"void quicksort(int *arr, int start, int end);JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { return JNI_VERSION_1_6;}JNIEXPORT void JNICALL Java_com_example_liyuanjing_jniproject_NativeSorting_nativeSort (JNIEnv *env, jobject obj, jintArray data) { jint* array = (*env)->GetIntArrayElements(env, data, 0); jint length = (*env)->GetArrayLength(env, data); quicksort(array, 0, length); (*env)->ReleaseIntArrayElements(env, data, array, 0);}void quicksort(int *arr, int start, int end){ int i, j, temp; for (i = 0; i < end-1; i++) { for (j = 0; j < end - i-1; j++) { if (*(arr+j) < *(arr+j+1)) { temp = *(arr+j); *(arr+j) = *(arr+j+1); *(arr+j+1) = temp; } } }}
In this example, the functions GetIntArrayElements, GetArrayLength, and ReleaseIntArrayElements are specific JNI codes. The first function gets a local data pointer to pass the data to a common C function. The second function returns the data size. The third function tells the local JVM that the work has been completed, copy the array back to the original location. These functions are required because JNIEnv objects must be used to transmit complex data types from Java to JNI.
Note: Call GetIntArrayElements to return a jint pointer pointing to the data in the jintArray in the function. Next we can use the jint pointer as a normal int type pointer.
2. Implement JNI in Android
To run Android, you must copy Android under the NDK directory android-ndk-r10d \ samples \ native-activity \ jni directory. mk, and com_example_liyuanjing_jniproject_NativeSorting.h and array. c. In the same directory, you must change Android. mk values.
LOCAL_PATH: = $ (call my-dir)
Include $ (CLEAR_VARS)
LOCAL_MODULE: = sorting_jni
LOCAL_SRC_FILES: = array. c
Include $ (BUILD_SHARED_LIBRARY)
$ (Call import-module, android/native_app_glue)
1. LOCAL_PATH: = $ (call my-dir)
An Android. mk file must first define the LOCAL_PATH variable. It is used to search for source files in the Development tree. In this example, the macro function 'my-dir' is provided by the compilation system and used to return the current path (that is, the directory containing the Android. mk file ).
Ii. include $ (CLEAR_VARS)
CLEAR_VARS is provided by the compilation system, specifying that gnu makefile can clear many LOCAL_XXX variables for you (such as LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, etc ...),
Except LOCAL_PATH. This is necessary because all the compilation control files are in the same gnu make execution environment, and all the variables are global.
Iii. LOCAL_MODULE: = sorting_jni
The LOCAL_MODULE variable must be defined to identify each module you describe in the Android. mk file. The name must be unique and contain no spaces. Note that the compilation system automatically generates the appropriate prefix and suffix. In other words, a shared library module named 'sorting _ jni 'will generate the 'libsorting _ jni' file.
Important Notes
If you name the library 'libhelloworld', the compiling system will not add any lib prefix or generate libhelloworld. so, this is to support Android from the source code of the Android platform. mk file, if you do need to do so.
Iv. LOCAL_SRC_FILES: = array. c
The LOCAL_SRC_FILES variable must contain the C or C ++ source code files to be compiled and packaged into the module. Note that you do not need to list header files and contained files here, because the compilation system will automatically find the dependent files for you; just list the source code files directly transmitted to the compiler. [Note: The default C ++ source code file extension is '. cpp '. it is also possible to specify a different extension. As long as you define the LOCAL_DEFAULT_CPP_EXTENSION variable, do not forget the starting dot (that is, defined '. cxx', rather than 'cxx') (of course we will not change this step )]
5. include $ (BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY is a variable provided by the compilation system. It points to a GNU Makefile script (which should be shared_library.mk In the build/core directory) and is responsible for collecting information from the previous call to 'include $ (CLEAR_VARS, define all the information in the LOCAL_XXX variable and decide what to compile and how to perform it correctly. And generate a static library based on its rules. Similarly, for static databases.
After configuring a C header file, a. c file, and an Android. mk file, Enter CMD to the current directory. Enter the ndk-build command:
[Armeabi] Compile thumb: sorting_jni <= array. c
[Armeabi] SharedLibrary: libsorting_jni.so
[Armeabi] Install: libsorting_jni.so => libs/armeabi/libsorting_jni.so
If there is no accident, the above correct results will be displayed.
Create the jinLibs directory under the app/src/main/directory of the Android Studio project and copy the files in the generated libs directory to the JinLibs directory. As shown in:
Then, call this method to implement the JNI function of Android.
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 9
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 8
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 7
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 6
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 5
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 4
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 3
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 2
05-25 20:02:46. 720 32349-32349/com. example. liyuanjing. jniproject I/liyuanjinglyj: 1
The previous JNI example is only used for demonstration. Developers should use Arrays. sort () or Collections. sort () for sorting. Generally, you do not need to sort data locally because the Java implementation is fast enough.