first, JNI calls the Java objectOne of the features that JNI provides is the use of Java objects in local code. Includes: Creating a Java Class object and passing a Java object through a function. To create a Java class object, you first need to get the class using the Findclass/getobjectclass function, and then use the Getmethodid method to get the class's method ID, and then call the function. In the case of a function call between Java and Native code, if it is a simple type, that is, a built-in type, such as int, char, etc. is a value pass (pass by value), and the other Java objects are reference passes (pass by reference), these objects are referenced by the JVM Passed to the Native code. To invoke a method of a Java object in a local method: 1) Get the class of the Java object you need to access Findclass by passing the full class name in Java to find the Java Classgetobjectclass by passing in a Java reference in JNI to get the type of the reference 。 The difference between them is that the former requires you to know the full class name, which requires a reference to a class in JNI. 2) Get Methodid, call method Getmethodid get an instance of the ID of the method Getstaticmethodid get a static method ID 3) Get the property of the object Getfieldid get an instance of the domain ID Getstaticfieldid get a static domain Idjni by ID identifies the domain and method, and the ID of a domain or method is a required parameter for any function that processes the domain and method.
second, the life cycle of the Java object referenced in the JNIJava objects are passed as references to local methods, and all references to these Java objects have a common parent type of jobject (equivalent to the object class in Java being the parent class of all classes). These object references have their life cycles. References to Java objects in JNI are categorized by life cycle: Global references, local references, weak global reference 1, local Reference native references, function calls to Jobject or jobejct created by JNI functions, are local references. The feature is that once the JNI layer function returns, Jobject is garbage collected, so it needs to be aware of its life cycle. You can force calls to deletelocalref for immediate recycling. Jstring pathstr = env->newstringutf (Path) .... env->deletelocalref (PATHSTR); 2, global Reference globally referenced, such objects do not voluntarily release, It will never be created by garbage collection: Env->newglobalref (obj); Release: Env->deleteglobalref (obj) If you want to continue using the parameters provided by the JVM after a Native code is returned, or if the return value of the JNI function is called in the procedure (such as G_mid), set the object to global Refe Rence, you can only use this global reference in the future; if it is not a jobject, you do not need to do so. 3, Weak Global Reference weakly globally referencing a special global Reference, which may be garbage collected during operation, it is important to be aware of its lifecycle and possible garbage collection at any time, such as low memory. Before use, the issameobject of jnienv can be used to determine whether it is recycled env->issameobject (OBJ1,OBJ2);
third, call Java object in local threadThe problem 1:jnienv is a thread-dependent variable jnienv is unique for each thread jnienv *env pointers can not be shared for multiple threads: But the JAVAVM pointer of a Java virtual machine is common to the entire JVM, We can get the jnienv pointer of the current thread through JAVAVM. You can use Javaattachthread to ensure that you get the JNI environment variable for the current thread static JAVAVM *gs_jvm=null;gs_jvm-> Attachcurrentthread (void * *) &env, NULL);//Append the current thread to a Java Virtual machine Jclass cls = Env->getobjectclass (Gs_object); Jfieldid fieldptr = Env->getfieldid (CLS, "value", "I"); Issue 2: You cannot directly save the Jobject pointer in one thread to a global variable and then use it in another thread. Workaround: Create a global variable with ENV->NEWGLOBALREF, save the incoming obj (local variable) to the global variable, and other threads can manipulate the Java object using this global variable note: This is not required if it is not a jobject. For example: Jclass is a subclass inherited by Jobject public, so it is of course a jobject and needs to create a global reference for later use. and Jmethodid/jfieldid and Jobject have no inheritance relationship, it is not a jobject, just an integer, so there is no problem of being released or not, can be saved directly after use. Static Jobject Gs_object=null; Jniexport void Jnicall Java_test_setenev (jnienv *env, Jobject obj) {&NBSP;&NBSP;&NBSP;&NBSP;ENV->GETJAVAVM (&gs _JVM); Saving to a global variable jvm //the direct assignment of obj to a global variable is not possible, the following function should be called: gs_object =env->newglobalref (obj);} The jni section code is as follows:#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> #include <jni.h>
#include <android/log.h> #define Logi (...) (void) __android_log_print (android_log_info, "native-activity", __va_args__)) #define LOGW (...) (void) __android_log_print (Android_log_warn, "native-activity", __va_args__)) #define LOGE (...) (void) __android_log_print (android_log_error, "native-activity", __va_args__)) //global variable JAVAVM *G_JVM = NULL; Jobject g_obj = null;void *thread_fun (void* Arg) { jnienv *env; jclass Cls; jmethodid mid; // Attach main thread if ((*G_JVM)->attachcurrentthread (G_JVM, &env, NULL)! = JNI_OK) { loge ("%s:attachcurrentthread () Failed ", __function__); return null; } //find the corresponding class cls = (*env)->GeTobjectclass (env,g_obj); if (cls = = NULL) { loge ("Findclass () Error ..."); goto error; } //methods in the class mid = (*env)->getmethodid (env, CLS, "Fromjni", "(I) V"); if ( Mid = = NULL) { loge (" Getmethodid () Error ... goto error; } //Last Call to static methods in Java (*env)->callvoidmethod (env, CLS, Mid, (int) arg); error: //detach main thread if ((*G_JVM)->DetachCurrentThread (g_ JVM)! = JNI_OK) &Nbsp; { loge ("%s: Detachcurrentthread () failed ", __function__); } pthread_exit (0); } //called by Java to create a child thread jniexport void Java_com_test_ Jnithreadtestactivity_mainthread (jnienv* env, Jobject obj, jint threadnum) { int I ; pthread_t* pt; pt = (pthread_t*) malloc (ThreadNum * sizeof (pthread_t)); for (i = 0; i < threadnum; i++) { //Create Child thread pthread_create (&pt[i], NULL, &thread_fun, (void *) i);} for (i = 0; i < threadnum; i++) {Pthread_join (pt[i], NULL);} LOGE ("Main thread exit ..."); //is called by Java to establish the JNI environment Jniexport void java_com_test_jnithreadtestactivity_setjnienv (jnienv* enV, jobject obj) { //Save the global JVM for use in sub-threads (*env) GETJAVAVM (ENV,&G_JVM); //cannot be directly assigned (G_obj = obj) g_obj = (*env)->newglobalref (env,obj) } //when the dynamic library is loaded this function is called by the system jniexport Jint Jnicall JNI_ OnLoad (JAVAVM *vm, void *reserved) { jnienv* env = null; jint result =-1; //gets the JNI version if ((*VM)->GETENV (VM, (void**) &env, jni_version_1_4)! = JNI_OK) { loge ("GetEnv failed!"); return result; } return jni_version_1_4; } requires all source code, you can open this link to download http:// Download.csdn.net/detail/mfcai_blog/5772377 This article welcome reprint, Reprint please indicate source and author Source: Http://blog.sina.com.cn/staratsky Author: Meteor
Learn more about JNI on the Android platform---Local multithreaded calls to Java code