In-depth understanding of jni on the android platform-calling java code using local Multithreading

Source: Internet
Author: User
Tags java reference

I. jni calls java objects

One of the functions provided by JNI is to use Java objects in local code. Including creating a java class object and passing a java object through a function. To create a java class object, first obtain the class using the FindClass/GetObjectClass function, then use the GetMethodID method to obtain the method id of the class, and then call the function. When calling a function between Java and Native code, if it is a simple type, that is, a built-in type, such as int or char, It is a pass by value ), other Java objects reference and pass by reference). These object references are passed to Native code by JVM.

To call a Java object method in a local method:

1) Get the class of the Java object you want to access

FindClass: by passing the complete class name in java, it is found that the java class is low.

GetObjectClass gets the reference type by passing in a java reference in jni.

The difference between them is that the former requires you to know the complete class name, and the latter requires a class reference in Jni.

2) Obtain MethodID and call the Method

GetMethodID obtains the ID of an instance's method.

GetStaticMethodID obtains the ID of a static method.

3) Get Object Attributes

GetFieldID to obtain the ID of an instance's domain

GetStaticFieldID obtains the ID of a static domain.

JNI uses ID to identify the domain and method. The ID of a domain or method is a required parameter for any function that processes the domain and method.

Ii. lifecycle of java objects referenced in jni

Java objects are passed as references to local methods. All references to these Java objects share a common parent type jobject (equivalent to the same as the Object class in java is the parent class of all classes ). These object references all have their lifecycles. References to Java objects in JNI are divided into global references, local references, and weak global references according to the life cycle.

1. Local Reference,

The jobejct created by the jobject or jni function is referenced locally when the function is called.

This feature is that once the JNI layer function returns, jobject is reclaimed from the garbage collection, so you need to pay attention to its lifecycle. You can forcibly call DeleteLocalRef for immediate recovery.

Jstring pathStr = env-> NewStringUTF (path)

....

Env-> DeleteLocalRef (pathStr );

2. Global Reference. If an object is not released, it will never be recycled.

Create: env-> NewGlobalRef (obj );

Release: env-> DeleteGlobalRef (obj)

If you want to continue using the parameters provided by JVM after a Native code is returned, or the return value of JNI function called, such as g_mid, is set to global reference, you can only use this global reference later. If it is not a jobject, you do not need to do this.

3. Weak Global Reference of Weak Global Reference

A special Global Reference may be decommissioned during running. Therefore, be sure to pay attention to its life cycle and garbage collection at any time, for example, when the memory is insufficient.

Before use, you can use the IsSameObject of JNIEnv to determine whether it is recycled.

Env-> IsSameObject (obj1, obj2 );

3. Calling java objects in a local thread

Question 1:

JNIEnv is a thread-related variable.

JNIEnv is unique for each thread

JNIEnv * The env pointer cannot be shared by multiple threads.

Solution:

However, the JavaVM pointer of the Java Virtual Machine is shared by the entire jvm. We can use JavaVM to obtain the JNIEnv pointer of the current thread.

You can use javaAttachThread to obtain the Jni environment variable of the current thread.

Static JavaVM * gs_jvm = NULL;

Gs_jvm-> AttachCurrentThread (void **) & env, NULL); // attaches the current thread to a Java Virtual Machine

Jclass cls = env-> GetObjectClass (gs_object );

JfieldID fieldPtr = env-> GetFieldID (cls, "value", "I ");

Question 2:

You cannot directly Save the jobject pointer in a thread to a global variable and use it in another thread.

Solution:

Use env-> NewGlobalRef to create a global variable and save the imported obj (local variable) to the global variable. Other threads can use this global variable to manipulate this java object.

Note: This is not required if it is not a jobject. For example:

Jclass is a subclass inherited from jobject public, so it is of course a jobject. You need to create a global reference for future use.

JmethodID/jfieldID has no inheritance relationship with jobject. It is not a jobject, but an integer. Therefore, there is no release issue. It can be saved and used directly.

Static jobject gs_object = NULL;

JNIEXPORT void JNICALL Java_Test_setEnev (JNIEnv * env, jobject obj)

{

Env-> GetJavaVM (& gs_jvm); // save it to the global variable JVM

// Directly assigning values to obj to global variables is not acceptable. You should call the following function:

Gs_object = env-> NewGlobalRef (obj );

}

The jni 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;

}

// Obtain the method in the class

Mid = (* env)-> GetMethodID (env, cls, "fromJNI", "(I) V ");

If (mid = NULL)

{

LOGE ("GetMethodID () Error .....");

Goto error;

}

// Call the static method in java

(* Env)-> CallVoidMethod (env, cls, mid, (int) arg );

Error:

// Detach the main thread

If (* g_jvm)-> DetachCurrentThread (g_jvm )! = JNI_ OK)

{

LOGE ("% s: DetachCurrentThread () failed", _ FUNCTION __);

}

Pthread_exit (0 );

}

// Called by java to create a subthread

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 a subthread

Pthread_create (& pt [I], NULL, & thread_fun, (void *) I );

}

For (I = 0; I <threadNum; I ++ ){

Pthread_join (pt [I], NULL );

}

LOGE ("main thread exit .....");

}

// Build the JNI environment by calling java

JNIEXPORT void Java_com_test_JniThreadTestActivity_setJNIEnv (JNIEnv * env, jobject obj)

{

// Save global jvm for use in child threads

(* Env)-> GetJavaVM (env, & g_jvm );

// Values cannot be directly assigned (g_obj = obj)

G_obj = (* env)-> NewGlobalRef (env, obj );

}

// This function is called by the system when the dynamic library is loaded

JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved)

{

JNIEnv * env = NULL;

Jint result =-1;

// Obtain 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;

}

You can open this link to download all source code.

Http://download.csdn.net/detail/mfcai_blog/5772377

You are welcome to repost this article. For more information, see the source and author.

Source: http://blog.sina.com.cn/staratsky

Author: meteor














































































































































This article is from the "Meteor blog" blog, please be sure to keep this source http://staratsky.blog.51cto.com/2513234/1251639

Related Article

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.