一、jobject和jclass
1.如果定义native方法时使用了static关键字,那么生成的头文件里就会传入jclass,代表这个类的引用。
2.如果没有使用static关键字,那么就会传入jobject,代表类的对象的引用。
二、jni回调java
先贴代码
1.java
package com.example.testcallback;
import android.util.Log;
public class TestCallbackManager {
private final String TAG = "TestCallbackManager";
static {
System.loadLibrary("TestCallback");
}
public native void start();
public void myCallback(int a) {
Log.e(TAG, "Callback: " + a);
}
}
2.生成的头文件
ps:如果native方法定义成static,这里就不是jobject,而是jclass
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_testcallback_TestCallbackManager */
#ifndef _Included_com_example_testcallback_TestCallbackManager
#define _Included_com_example_testcallback_TestCallbackManager
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_testcallback_TestCallbackManager
* Method: start
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_testcallback_TestCallbackManager_start
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
3.c文件
#include <jni.h>
#include <android/log.h>
#include "com_example_testcallback_TestCallbackManager.h"
#define TAG "TestCallbackJNI"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
JNIEXPORT void JNICALL Java_com_example_testcallback_TestCallbackManager_start
(JNIEnv *env, jobject obj) {
__android_log_print(ANDROID_LOG_ERROR, "Callback JNI", "begin");
jclass clazz = (*env)->GetObjectClass(env, obj);
jmethodID mID = (*env)->GetMethodID(env, clazz, "myCallback", "(I)V");
(*env)->CallVoidMethod(env, obj, mID, 10);
__android_log_print(ANDROID_LOG_ERROR, "Callback JNI", "end");
}
4.解释c文件
(1)在同一个类中,定义native方法和要调用的callback方法,为的是可以在当前的对象引用obj中找到当前类的引用,然后找到这个回调方法。
(2)GetObjectClass,通过obj找到当前类。
(3)GetMethodID找到回调方法,参数:env引用,类引用,方法名,字段描述符(这里看第四条)
(4)字段描述符:
(a)JNI中描述字段使用字段描述符,描述方法同样有方法描述符。一个方法描述符包含参数类型和返回值类型。参数类型出现在前面,并由一对圆括号将它们括起来,参数类型按它们在方法声明中出现的顺序被列出来,并且多个参数类型之间没有分隔符。如果一个方法没有参数,被表示为一对空圆括号。方法的返回值类型紧跟参数类型的右括号后面。
(b)描述符对应符号:
Boolean~~~Z
Byte~~~B
Char~~~C
Short~~~S
Int~~~I
Long~~~J
Float~~~F
Double~~~D
Void~~~V
objects对象:
以”L”开头,以”;”结尾,中间是用”/” 隔开的包及类名。比如:Ljava/lang/String;。嵌套类:Ljava/xx/外部类名$内部类名;
(c)方法描述符中可能会包含类描述符,如方法native private String getLine(String);的描述符为:“(Ljava/lang/String;)Ljava/lang/String;”
(d)数组类型的描述符以“[”开头,后面跟着数组元素类型的描述符。如,public static void main(String[] args);的描述符是:”([Ljava/lang/String;)V”
(e)举例:
// 描述符:(IFDZ)V
public void method1(int a,float f,double b,boolean b){
}
// 描述符:(Ljava/lang/String;)I
public int method2(String s){
return 0;
}
//描述符:()[I
public int[] method3(){
return null;
}
(5)CallVoidMethod 调用回调方法,并传入相应值。