Android JNI dynamic registration

  • Dynamic and static registration
  • Dynamic registration
  • JNI thread

Dynamic and static registration

  • Static registration: Usually the default is static registration

Such as:

Static registration:

  • Advantages: simple to use, convenient in the program will run when the initial call
  • Disadvantages: Long class name, bundled with the class name, once changing the package name will be more troublesome

Dynamic registration

  • Advantages: Initialization at the beginning of the run, simple code
  • Disadvantages: More troublesome to use.

Static registration is not mentioned, this article mainly introduces dynamic registration

Dynamic registration

Dynamic registration is like calling the constructor of a class, which initializes all methods every time it is first run

In this method, complete all initializations in the Activity!

jint JNI_OnLoad(JavaVM *javaVm, void *) {
 	// Return the JNI version number
	return JNI_VERSION_1_6;
}
Copy the code

JNI_OnLoad source code:

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
Copy the code

Step 1: Get the Env from the JVM, if returned! =0: Failed to get Env note :JVM is unique

// Get Env in the jVM
    int result = javaVm->GetEnv(reinterpret_cast<void **>(&jniEnv), JNI_VERSION_1_6);

    //result ! = 0 fails
    if(result ! = JNI_OK) {/ / fail
        return - 1;
    }
Copy the code

This code is relatively simple not to say!

Step 2: Dynamically register the methods to be initialized with Env

/ / get jclass
    jclass thread_class = jniEnv->FindClass(path);
    /** * source code: * jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, Jint nMethods) * Parameter one :class * Parameter two: structure array * parameter three: structure size */
    jniEnv->RegisterNatives(thread_class, jniNativeMethod,
                            sizeof(jniNativeMethod) / sizeof(JNINativeMethod));
Copy the code
  • Parameter 1: jclass
  • Parameter 2 :JNINativeMethod structure
typedef struct {
    const char* name;		/ / the method name
    const char* signature;	/ / signature
    void*       fnPtr;		// The callback function
} JNINativeMethod;
Copy the code
  • Parameter 3 :JNINativeMethod Array length

Corresponding code of parameter 2:


void javaDynamicRegist(JNIEnv *jniEnv, jobject jobj) {
    LOGE("javaDynamicRegist")}int javaDynamicRegist2(JNIEnv *jniEnv, jobject jobj, jstring name) {
    const char *name2 = jniEnv->GetStringUTFChars(name, nullptr);
    LOGE("javaDynamicRegist2%s\n", name2);
    return 200;
}

/** typedef struct { const char* name; // Call name const char* signature; // Sign void* fnPtr; } JNINativeMethod; * /
static const JNINativeMethod jniNativeMethod[] = {
        {"nativeDynamicRegist"."()V",                   (void *) javaDynamicRegist},
        {"nativeDynamicRegist2"."(Ljava/lang/String;) I", (void *) javaDynamicRegist2},
};
Copy the code

Auxiliary graph:



Use:



Here native method error does not matter, this is normal state!

The running results are as follows:

2021- 04- 30 16:57:03.098 330- 330./com.example.jni E/native layer: javaDynamicRegist2021- 04- 30 16:57:03.098 330- 330./com.example.jni E/native layer: javaDynamicRegist2 li Yuan BaCopy the code

JNI thread

In C/C++, threads use pThreads

Pthread function instructions
pthread_create() The creation thread starts running the related thread function and exits when it finishes
pthread_eixt() Because exit() is used to end the process, a thread-specific terminating function is required
pthread_join() Suspend the current thread, used to block waiting for the thread to terminate, and return immediately if the thread has terminated, 0= success
pthread_cancel() Sending a termination signal to the thread returns 0 on success, but success does not mean that the thread will terminate

Reference documentation

Auxiliary code diagram:



Remember to guide the package:

#include <pthread.h>
Copy the code

Pthread_create () :

  • Parameter 1: thread ID
  • Parameter 2: Thread attribute (usually 0 or NULlptr)
  • Parameter 3: Function callback
  • Parameter 4: The value passed

Why set Jobject as a global variable? A: Jobject cannot span threads or functions.

Function callback:

void *my_thread_action(void *pVoid) {
    MyThread *thread = static_cast<MyThread *>(pVoid);
    /** * The JVM has only one jNIEnv solution: */
    JNIEnv *newJniEnv = nullptr;
    /** * jint AttachCurrentThread(JNIEnv** p_env, void* thr_args
    jint result = ::jvm->AttachCurrentThread(&newJniEnv, nullptr);

    // Result == 0 indicates success
    if(result ! = JNI_OK) {return 0; // Attach failed, return
    }

    jclass j_c = newJniEnv->GetObjectClass(thread->jobj);
    jmethodID j_id = newJniEnv->GetMethodID(j_c, "isThread"."()V");
    // Call the Java layer isThread method
    newJniEnv->CallVoidMethod(thread->jobj, j_id);

    // Unattach
    ::jvm->DetachCurrentThread();
    // The reference cannot be released directly
    return nullptr;
}
Copy the code

The JVM is retrieved when JNI_OnLoad is initialized

jint JNI_OnLoad(JavaVM *javaVm, void *) {
	 ::jvm = javaVm;
 }
Copy the code

:: JVM is equivalent to this.jvm in Java

Finally calling the Java layer method:



Effect:

Note:

If the so library returns an error, comment out the other two

In the same way, if you want to see JNI basic use (native simp-lib.cpp) code, then JNI advanced and QQ voice practice code comment out!

Only one CPP file can now exist

The complete code

Other JNI articles:

Introduction to Android JNI

Android JNI :Android JNI

Android JNI QQ funny voice combat (including complete Demo)

Chapter 5 :JNI exception catching and handling

Original is not easy, your praise is my biggest support ~