JNI(2)

JNI是Android系统中Java与Native交互的桥梁


数据类型的转换

Java Native Signature
byte jbyte B
char jchar C
double jdouble D
float jfloat F
int jint I
short jshort S
long jlong J
boolean jboolean Z
void void V
String jstring Ljava/lang/String;

Java具有重载方法,可以定义方法名相同,但参数不同的方法,所以通过方法签名和方法名就可以找到对应的Java方法。

但是方法签名比较难写,可以使用如下方法:

1
2
3
javac xxx.java
javap -s -p xxx.class
//其中s 表示输出内部类型签名,p表示打印出所有的方法和成员

JNIEnv

JNIEnv 是一个指向全部JNI方法的指针,该指针只在创建它的线程有效,不能跨线程传递,因此,不同线程的JNIEnv是彼此独立,可以调用Java的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
//libnativehelper/include_jni/jni.h
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;//C++中JNIEnv的类型
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;//C中JNIEnv的类型
typedef const struct JNIInvokeInterface* JavaVM;
#endif

------------------------------------------------------------------------

jfieldID GetFieldID(jclass clazz,const char *name,const char *sig);
jmethodID GetFieldID(jclass clazz,const char *name,const char *sig);

其中GetFieldID方法的三个参数:

  • jclass代表Java类
  • name代表成员方法或者成员变量的名字
  • sig为这个方法和变量的签名

通过JavaVM的AttachCurrentThread函数可以获取这个线程的JNIEnv,可以在不同的线程中调用Java方法,在使用AttachCurrentThread函数的线程退出前,调用DetachCurrentThread函数来释放资源。

MediaRecorder JNI层 举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//frameworks/base/media/jni/android_media_MediaRecorder.cpp
static void android_media_MediaRecorder_native_init(JNIEnv *env){
jclass clazz;
clazz = env->FindClass("android/media/MediaRecorder");
if (clazz == NULL) {
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.context == NULL) {
return;
}
fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
if (fields.surface == NULL) {
return;
}
jclass surface = env->FindClass("android/view/Surface");
if (surface == NULL) {
return;
}
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
return;
}
}

//通过fields_t结构体,保存这些变量,方便下次使用
struct fields_t {
jfieldID context;
jfieldID surface;
jmethodID post_event;
};
static fields_t fields;


//可以看出,使用了fields.post_event
void JNIMediaRecorderListener::notify(int msg, int ext1, int ext2){
ALOGV("JNIMediaRecorderListener::notify");
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL);//1
}


参考:

http://liuwangshu.cn/tags/Android%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3JNI/