Several important points NDK Development

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/Kennethdroid/article/details/88356469

Here Insert Picture Description

This article first appeared in the public micro-channel number "byte floating"

NDK development of this blog series:

In general steps Native Java object access layer

Java objects may be freely accessed through the JNI Native layer, Java objects are generally divided into three access steps.

    1. By GetObjectClassor FindClassacquired class object reference;
    1. By GetXXMethodID, GetXXFieldIDMethods acquired Java object access methods and properties of the ID;
    1. By CallXXMethod, GetXXField, SetXXFieldMethods achieve access to the Java object method calls and properties.

A simple example.

package com.byteflow.framework;

public interface NDKCallback {
    void onProcessorCallback(int processorUId, int errorCode, Object objResult);
}
//获取到 class 对象的引用
jclass callbackClass = env->GetObjectClass(callbackObj);

//获取到 Java 对象方法的访问 ID
mOnProcessorCallbackMID = env->GetMethodID(callbackClass, "onProcessorCallback", "(IILjava/lang/Object;)V");

//调用 Java 对象的方法
env->CallVoidMethod(callbackObj, mOnProcessorCallbackMID, processorUID, errCode, objResult);

When accessing the JNI using Java objects, and the reference value is passed to note the distinction between transmission, such as basic types jint, jchar, jdouble like are passed by value, and jstring, jobject, etc. to reference.

另外,注意区分 FindClass 和 GetObjectClass 两个 JNI 方法的使用。FindClass 只需要完整的类名便可获得 class 对象的引用,而 GetObjectClass 通过 JNI 传入的一个 Java 对象的引用来获取 class 对象的引用。

在 Native 层中 Java 对象的引用类型

在 JVM 中 Java 对象的引用类型分为 “强、软、弱、虚” ,我们常用的一般是弱引用,而在 Native 层中 Java 对象的引用类型一般分为 3 种,即 LocalReference 、GlobalReference 、WeakGlobalReference 。

LocalReference 称为本地引用或局部引用,JNI 传入的 jobject 以及利用 JNI 函数创建的临时 jobject 对象一般是本地引用,其特点是一旦 JNI 调用完成,jobject 对象就会被回收掉,但可能不会被立即回收,需要注意其生命周期,强制立即回收调用 env->DeleteLocalRef(obj);

GlobalReference 称为全局引用,其特点是如果不主动释放,在进程生命周期里其对应的对象一直不会被回收。由此可见,全局引用若使用不当容易造成内存泄漏,全局引用的使用和释放应成对出现:

//创建
env->NewGlobalRef(g_obj);

...

//释放
env->DeleteGlobalRef(g_obj);

其使用场景是,在 JNI 调用完成后,想要继续使用 jobject 对象,需要将其设置为 GlobalReference 。

WeakGlobalReference 称为弱全局引用,其特点是在程序运行期间,该引用对应的对象随时可能会被 GC 回收(如内存不足时),需要谨慎使用。

JNIEnv 和 JavaVM 类型的作用域

JNIEnv 这个结构体比较特殊,主要提供 JNI 调用环境,JNIEnv 类型的变量是线程相关,即一个线程会对应一个 JNIEnv 变量,也就是说 JNIEnv 类型的指针不能在不同的线程中共用。

To access Java objects in a sub-thread, it is necessary to obtain the corresponding JNIEnv type variable pointer by AttachCurrentThread, DetachCurrentThreadacquired and released.

JavaVM type of variable is related to the process, namely a Java virtual machine corresponds to a variable of type JavaVM, through env->GetJavaVM(&g_jvm);available JavaVM pointer of the current process.

A simple example.

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public void callbackFromJNI(int errCode, Object result) {
        Log.d(TAG, "callbackFromJNI() called with: errCode = [" + errCode + "], result = [" + result + "]");
    }
}
//全局变量
JavaVM *g_jvm = NULL;
jobject g_obj = NULL;

void *posix_run(void* arg)
{
    JNIEnv *env;
    jclass cls;
    jmethodID mid;

	//Attach 当前线程获取 JNIEnv
	if(g_jvm->AttachCurrentThread(&env, NULL) != JNI_OK)
	{
		return NULL;
	}

	//获取 class 对象
	cls = env->GetObjectClass(g_obj);

	//获取 MethodID
	mid = env->GetMethodID(cls, "callbackFromJNI", "(ILjava/lang/Object;)V");

	//调用对象方法
	env->CallVoidMethod(cls, mid , 0, NULL);

	//Detach 当前线程
	g_jvm->DetachCurrentThread();

	return NULL;
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_byteflow_ndk_MainActivity_stringFromJNI(JNIEnv* env, jobject obj) {

	//获取 JavaVM
	env->GetJavaVM(&g_jvm);

	//创建对象的全局引用
	g_obj = env->NewGlobalRef(obj);

	pthread_t tid;
	//创建子线程
	pthread_create(&tid, NULL, &posix_run, NULL);

	//阻塞主线程等待子线程结束
	pthread_join(tid, NULL);

	//释放对象的全局引用
	env->DeleteGlobalRef(g_obj);
    return NULL;
}

Contacts and exchanges

Micro-channel public number of
My public number
individual micro letter
My WeChat

Guess you like

Origin blog.csdn.net/Kennethdroid/article/details/88356469