目录
上一篇 深入浅出Android NDK之JNI数组操作
对象操作包括以内容:
创建对象
调用对象函数
获取/设置对象属性
不管哪种操作,首先需要获得类对象jclass。
jni提供了两个API可以获得jclass对象:
jclass FindClass(const char* name);
jclass GetObjectClass(jobject obj);
大部分情况下我们都会通过FindClass来获得jclass对象:比如:
env->FindClass("java/lang/String");
env->FindClass("android/graphics/Bitmap");
env->FindClass("android/view/Button");
FindClass的name参数其实就是包名加类名,然后把.用/代替。
在已经拥有jobject的情况下,我们可以直接调用GetObjectClass来得到其类对象。
得到jclass对像有什么用呢?jclass主要可以用来获得方法ID和成员变量ID。
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig);
jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig);
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig);
jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig);
下面我们看一个例子,假有如下Java类:
package com.example.objtest;
public class ObjTest {
private int mID;
private static int sCount;
public int getID() {
return mID;
}
public void setID(int id) {
mID = id;
}
public static int getCount() {
return sCount;
}
public static void setCount(int count) {
sCount = count;
}
}
我们可以:
jclass cls = env->FindClass("com/example/objtest/ObjTest");
jmethodID mid1 = env->GetMethodID(cls, "<init>","()V");//默认构造函数
jmethodID mid2 = env->GetMethodID(cls, "<init>","(I)V");//构造函数public ObjTest(int id)
jfieldID fid1 = env->GetFieldID(cls, "mID","I");
jmethodID mid3 = env->GetMethodID(cls, "getID","()I");
jmethodID mid4 = env->GetMethodID(cls, "setID","(I)V");
jfieldID fid2 = env->GetStaticFieldID(cls, "sCount","I");
jmethodID mid5 = env->GetStaticMethodID(cls, "getCount","()I");
jmethodID mid6 = env->GetStaticMethodID(cls, "setCount","(I)V");
不管是方法ID还是成变变量ID,除了函数名称以外,我们还需要传入签名,签名的用法之前我们已经讲过,不清楚的可以看之前的文章:
深入浅出Android NDK之使用RegisterNatives函数动态注册native函数
特别需要注意的是对于构造函数,函数的名称固定为,返回值为void。所以构造函数的签名的返回值类型都是V。
有了方法ID和成员变量ID,之后的事情就好办多了,我们看以下例子:
jclass cls;
jmethodID mid;
jfieldID fid;
int id;
cls = env->FindClass("com/example/objtest/ObjTest");
/*ObjTest test = new ObjTest(1);*/
mid = env->GetMethodID(cls, "<init>","(I)V");
jobject test = env->NewObject(cls, mid, 1);
/*id = test.getID()*/;
mid = env->GetMethodID(cls, "getID","()I");
id = env->CallIntMethod(test, mid);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "test.getID() return %d", id);
/*test.setID(2);*/
mid = env->GetMethodID(cls, "setID", "(I)V");
env->CallVoidMethod(test, mid, 2);
/*test.mID = 3;*/
fid = env->GetFieldID(cls, "mID", "I");
env->SetIntField(test, fid, 3);
/*id = test.mID*/
id = env->GetIntField(test, fid);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "test.mID is %d", id);
我们可以调用NewObject函数创建java对象,构建的时候需要传入构造方法ID和参数:
对象创建完成之后我们就可以调用对象的函数了,在调用函数之前我们首先要确定函数的返回值类型,根据返回值类型来确定调用CallMethod的哪个变体,共有以下变体:
jboolean CallVoidMethod(jobject, jmethodID, ...);
jboolean CallBooleanMethod(jobject, jmethodID, ...);
jbyte CallByteMethod(jobject, jmethodID, ...);
jchar CallCharMethod(jobject, jmethodID, ...);
jshort CallShortMethod(jobject, jmethodID, ...);
jint CallIntMethod(jobject, jmethodID, ...);
jlong CallLongMethod(jobject, jmethodID, ...);
jobject CallObjectMethod(jobject, jmethodID, ...);
成员变量也类似,确定了成员变量的类型后,再调用
void SetField( jobject, jfieldID, );
GetField( jobject, jfieldID);
来存/取相应的成员变量。
对于静态函数和静态成员变量的调用也类似,对于静态函数和静态成员变量需要调用staitct版本的函数,且因为是静态,所以不需要对象,直接通过jclass调用即可。
jclass cls;
jmethodID mid;
jfieldID fid;
int count;
cls = env->FindClass("com/example/objtest/ObjTest");
/*count = ObjTest.getCount()*/;
mid = env->GetStaticMethodID(cls, "getCount","()I");
count = env->CallStaticIntMethod(cls, mid);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "ObjTest.getCount() return %d", count);
/*test.setCount(2);*/
mid = env->GetStaticMethodID(cls, "setCount", "(I)V");
env->CallStaticVoidMethod(cls, mid, 2);
/*test.sCount = 3;*/
fid = env->GetStaticFieldID(cls, "sCount", "I");
env->SetStaticIntField(cls, fid, 3);
/*int count = test.sCount*/
count = env->GetStaticIntField(cls, fid);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "test.sCount is %d", count);
下面我们总结一下,创建对象步骤:
- env->FindClass得到jclass
- env->GetMethodID得到构造方法的jmethodID
- env->NewObject(jclass,jmethodID,参数)
调用实例方法的步骤:
- env->FindClass得到jclass
- env->GetMethodID得到构造方法的jmethodID
- env->CallXXXMehtod(jobject, jmethodID,参数)
设置成员变量步骤:
- env->FindClass得到jclass
- env->GetFieldID得到成员变量的jfieldID
- env->SetXXXFileld(jobject, jfieldID,值)
获得成员变量步骤:
- env->FindClass得到jclass
- env->GetFieldID得到成员变量的jfieldID
- env->GetXXXFileld(jobject, jfieldID)
总结:
- 得到jclass
- 从jclass中得到ID
- 确定类型,调用相应函数
下一篇 深入浅出Android NDK之异常处理