一.JNI设计的目的
1.c/c++不同点在JNI
- Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
- jobject thiz )
- {
- return (*env)->NewStringUTF(env, "Hello World from JNI!");
- }
Java | C/C++ | 字节数 |
boolean | jboolean | 1 |
byte | jbyte | 1 |
char | jchar | 2 |
short | jshort | 2 |
int | jint | 4 |
long | jlong | 8 |
float | jfloat | 4 |
double | jdouble | 8 |
对于数组型参数,
Java | C/C++ |
boolean[ ] | JbooleanArray |
byte[ ] | JbyteArray |
char[ ] | JcharArray |
short[ ] | JshortArray |
int[ ] | JintArray |
long[ ] | JlongArray |
float[ ] | JfloatArray |
double[ ] | JdoubleArray |
对于上述类型数组,有一组函数与其对应。以下函数中 Xxx 为对应类型。
xxx * GetXxxArrayElements(xxxArray array, jboolean *isCopy)
产生一个指向 Java 数组元素的 C 指针。不再需要时,需将此指针传给 ReleaseXxxArrayElemes。
3.JNI相关操作
- 类的相关操作(获取类)
jclass FindClass(JNIEnv *env, const char *name); 查找类
需要注意的是第二个参数为const char*类型的,我们如果从Java从层传入unicode编码的jstring类型需要使用GetStringUTFChars函数转换成utf8的const char*,记得后面ReleaseStringUTFChars 函数,如果成功返回这个Java类的对象jclass.
jclass GetSuperclass(JNIEnv *env, jclass clazz); 获取父类或者说超类
该函数的第二个参数为jclass类,我们调用时传入的是子类,否则返回将是NULL
jboolean IsAssignableFrom(JNIEnv *env, jclass clazz1,jclass clazz2); 判断class1对象能否安全的强制转换为class2对象
jclass GetObjectClass(JNIEnv *env, jobject obj); 通过对象获取这个类
jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz); 判断对象是否为某个类的实例
- 调用Java方法 (call java的方法)
jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 获取一个Java方法的ID
这个函数将返回非静态类或接口实例方法的方法 ID
NativeType CallXXXMethod (JNIEnv *env, jobject obj,jmethodID methodID, va_list args); 调用XXX类型的Java 方法
执行Java类中某个方法,需要注意的是这个里的java类是非静态的,由于Java的方法的类型比较多,所以该函数可能有以下几种形式, 如 CallObjectMethod,CallBooleanMethod,CallByteMethod,CallCharMethod,CallShortMethod,CallIntMethod,CallLongMethod,CallFloatMethod,CallDoubleMethod和CallVoidMethod,
va_list args是代表参数列表。
- 访问Java对象的域
Java对象的域或者说字段、属性(Field) 类似方法的执行
1. jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig); 获取实例对象的域ID
2. NativeType GetXXXField(JNIEnv *env, jobject obj,jfieldID fieldID);
类似GetXXXMethod函数,可能有的类型有 GetObjectField,GetBooleanField,GetByteField,GetCharField,GetShortField,GetIntField,GetLongField,GetFloatField,GetDoubleField。
3. void SetXXXField(JNIEnv *env, jobject obj, jfieldID fieldID,NativeType value);
Java的域可以赋值的,可能有的类型有 SetObjectField,SetBooleanField,SetByteField,SetCharField,SetShortField,SetIntField,SetLongField,SetFloatField,SetDoubleField
4.jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
5. NativeType GetStaticXXXField(JNIEnv *env, jclass clazz,jfieldID fieldID);
6. void SetStaticXXXField(JNIEnv *env, jclass clazz,jfieldID fieldID, NativeType value);
4.Java层传入的String不能在JNI中直接转化为jstring,因为Java的内部编码为unicode,中英文的字符都是每个占两个字节,而jni中我们需要使用utf-8来表示,utf-8比较特殊中英文是不等长的,比如英文等符号的ascii占用一个字节,而中文则为三个字节,同时仍然以/n结尾
而正确的转换unicode到utf-8方法为使用GetStringUTFChars这个函数:
后面ReleaseStringUTFChars.
一.本文是主要写GetFieldID,GetMethodID方法的使用
jclass clazz=(*env)->GetObjectClass(env,thiz);//其中的clazz就是Natvie class.
void Java_com_android_jni_Native_getValue(JNIEnv * env,jobject thiz){
jfieldID fid;
jfieldID fNumberId;
jstring jstr;
jmethodID mid;
const char * szTemp;
jclass clazz=(*env)->GetObjectClass(env,thiz);
print(clazz);
fid=(*env)->GetFieldID(env,clazz,"value","Ljava/lang/String;");
if(fid==NULL){
return;
}
jstr=(*env)->GetObjectField(env,thiz,fid);
szTemp=(*env)->GetStringUTFChars(env,jstr,NULL);
print(szTemp);
(*env)->ReleaseStringUTFChars(env,jstr,szTemp);
jstr=(*env)->NewStringUTF(env,"hello world");
if(jstr==NULL)
return;
(*env)->SetObjectField(env,thiz,fid,jstr);
//call the method showMessage
fNumberId=(*env)->GetStaticFieldID(env,clazz,"number","I");
if(fNumberId==NULL)
return;
jint num=(*env)->GetStaticIntField(env,clazz,fNumberId);
//print(num);
(*env)->SetStaticIntField(env,clazz,fNumberId,2);
mid=(*env)->GetMethodID(env,clazz,"showMessage","()V");
if(mid==NULL)
return ;
(*env)->CallVoidMethod(env,thiz,mid);
}
开始我在写这个程序的时候一直报GetFileId ..No such "value".
找了好久才发现 我在Native.java中定义的 和getValue()也是用static
然后定义的value不是static.
在fid=(*env)->GetFieldID(env,clazz,"value","Ljava/lang/String;"); 报错,是因为static方法中必须要用static的变量
所以我把getValue()方法的static方法去掉,下面是ok的代码。
void Java_com_android_jni_Native_getValue(JNIEnv * env,jobject thiz){
jfieldID fid;
jfieldID fNumberId;
jstring jstr;
jmethodID mid;
const char * szTemp;
jclass clazz=(*env)->GetObjectClass(env,thiz);
print(clazz);
fid=(*env)->GetFieldID(env,clazz,"value","Ljava/lang/String;");
if(fid==NULL){
return;
}
jstr=(*env)->GetObjectField(env,thiz,fid);
szTemp=(*env)->GetStringUTFChars(env,jstr,NULL);
print(szTemp);
(*env)->ReleaseStringUTFChars(env,jstr,szTemp);
jstr=(*env)->NewStringUTF(env,"hello world");
if(jstr==NULL)
return;
(*env)->SetObjectField(env,thiz,fid,jstr);
//call the method showMessage
fNumberId=(*env)->GetStaticFieldID(env,clazz,"number","I");
if(fNumberId==NULL)
return;
jint num=(*env)->GetStaticIntField(env,clazz,fNumberId);
//print(num);
(*env)->SetStaticIntField(env,clazz,fNumberId,2);
mid=(*env)->GetMethodID(env,clazz,"showMessage","()V");
if(mid==NULL)
return ;
(*env)->CallVoidMethod(env,thiz,mid);
}
我本来想全部用static来解决就是
fid=(*env)->GetStaticFieldID(env,clazz,"value","Ljava/lang/String;");
不知道什么原因,还是出现上面的错误。。后续来改。
今天试getMethodId();
mid=(*env)->GetMethodID(env,clazz,"showMessage","()V");//showMessage为Java中的方法,"()V"为该方法是return void的方法。
(*env)->CallVoidMethod(env,thiz,mid);
与GetMethodID相对应的是Call**Method().
对应static的属性一定要用static的属性。
fNumberId=(*env)->GetStaticFieldID(env,clazz,"number","I");
if(fNumberId==NULL)
return;
jint num=(*env)->GetStaticIntField(env,clazz,fNumberId);
//print(num);
(*env)->SetStaticIntField(env,clazz,fNumberId,2);
参考网站学习
http://www.ibm.com/developerworks/cn/java/l-linux-jni/
http://dev.10086.cn/cmdn/bbs/redirect.php?tid=33663&goto=lastpost
http://www.android123.com.cn/androidkaifa/686.html