jni学习毕竟:
访问类对象的属性:
env 为 JNIEnv,obj的类型为jobject
JAVA_FieldAccessDemo_accessField(JNIEnv *env,jobject obj){
jfieldID fid;
jclass cls = (*env)->GetObjectClass(env, obj);
//类FieldAccessDemo中有个String类型的属性s
//获取要访问的属性的id
fid = (*env)->GetFieldID(evn,cls,"s","Ljava/lang/String;");
//读取属性值
jstring jstr = (*env)->GetObjectField(env,obj,fid);
char* str = (*evn)->GetStringUTFChars(env,jstr,NULL);
//释放资源
(*env)->ReleaseStringUTFChars(env,jstr,str);
//现在反过来,改变调用该本地方法的java对象的属性值
jstr = (*env)->NewStringUTF(env,"88888");
(*env)->SetObjectField(env,obj,fid,jstr);
}
总结:
1.
jfieldID fid = (*env)->GetFieldID(env,对象所属的类的jclass,
属性名,
属性对应的属性描述符号);
2.(*env)->GetObjectField(env,对象,属性id);
访问静态属性:
假如有个类如下:
class StaticFielcdAccess {
private static int si;
private native void accessField();
}
那么实现为:
JNIEXPORT void JNICALL
Java_StaticFieldAccess_accessField(JNIEnv *env, jobject obj)
{
jfieldID fid; /* store the field ID */
jint si;
jclass cls = (*env)->GetObjectClass(env, obj); //获取类class
fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); //获取静态属性id
si = (*env)->GetStaticIntField(env, cls, fid); //读去属性的值
(*env)->SetStaticIntField(env, cls, fid, 200); //设置静态属性的值
}
通过jni怎么去调用java层的类的实例方法和静态方法呢?
**************************1.访问实例方法**************************
假如有个这样的类:
class InstanceMethodCall {
private native void nativeMethod();
private void callback() {
System.out.println("In Java");
}
public static void main(String args[]) {
InstanceMethodCall c = new InstanceMethodCall();
c.nativeMethod();
} static {
System.loadLibrary("InstanceMethodCall");
}
}
jni实现:
JNIEXPORT void JNICALL
Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
//1.拿到class
jclass cls = (*env)->GetObjectClass(env, obj);
//2.拿到方法id
jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
//3.根据obj,和方法id 调用方法
(*env)->CallVoidMethod(env, obj, mid);
}
根据方法的返回值来决定调用哪个方法:
Call<Type>Method
如果返回int 那么最后一步就调用 (*env)->CallIntMethod(env,obj,mid);
最后那个参数 "()V" 是方法描述符:
(I)V 带一个int 类型的参数,返回值类型为void
()D 没有参数,返回double //注意!!没有参数并不是 (V)D
方法public static void main(String[] args) 对应的方法描的符为:
([Ljava/lang/String;)V
完整的方法描述符规则,http://java.sun.com/docs/books/jni/ 12.3.4章节
**************************2.访问静态方法**************************
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid =
(*env)->GetStaticMethodID(env, cls, "callback", "()V");
(*env)->CallStaticVoidMethod(env, cls, mid); //注意,这里跟访问实例方法的区别是 第二个参数不是obj,而是cls
**************************3.访问父类的方法,怎么搞?**************************
传当前调用对象obj,父类class,方法id
CallNonvirtualVoidMethod,
**************************4.怎么用jni API 来调用 java层的构造器?**************************
我们来看在linphone中它是怎么调用Android 里面的AudioRecord类的构造器的->
查看android API
http://developer.android.com/reference/android/media/AudioRecord.html
AudioRecord的构造器声明为:
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
在linphone源码库的submodules/linphone/mediastreamer2/src/msandroid.cpp的方法sound_read_setup中有这么一段代码:
static void sound_read_setup(MSFilter *f){
//...
jmethodID constructor_id=0;
//...
JNIEnv *jni_env = ms_get_jni_env();
//这里是拿到类AudioRecord对应的class
d->audio_record_class = (jclass)jni_env->NewGlobalRef(jni_env->FindClass("android/ media/AudioRecord"));
//构造方法毕竟还是构造方法,所以,思路肯定是要先拿到构造方法对应的methodId
//调用构造方法时,按调用实例方法的形式来调,只是第二个参数不再是构造方面名,而是<init>
//因为类AudioRecord的构造方法有5个int类型参数,所以第三个参数 为 (IIIII)V
constructor_id = jni_env->GetMethodID(d->audio_record_class,"<init>", "(IIIII)V");
//构造方法的methodId 拿到了那就可以创建对象了:
d->audio_record = jni_env->NewObject(d->audio_record_class
,constructor_id
,1/*MIC*/
,d->rate
,2/*CHANNEL_CONFIGURATION_MONO*/
,2/* ENCODING_PCM_16BIT */
,d->buff_size);
访问类对象的属性:
env 为 JNIEnv,obj的类型为jobject
JAVA_FieldAccessDemo_accessField(JNIEnv *env,jobject obj){
jfieldID fid;
jclass cls = (*env)->GetObjectClass(env, obj);
//类FieldAccessDemo中有个String类型的属性s
//获取要访问的属性的id
fid = (*env)->GetFieldID(evn,cls,"s","Ljava/lang/String;");
//读取属性值
jstring jstr = (*env)->GetObjectField(env,obj,fid);
char* str = (*evn)->GetStringUTFChars(env,jstr,NULL);
//释放资源
(*env)->ReleaseStringUTFChars(env,jstr,str);
//现在反过来,改变调用该本地方法的java对象的属性值
jstr = (*env)->NewStringUTF(env,"88888");
(*env)->SetObjectField(env,obj,fid,jstr);
}
总结:
1.
jfieldID fid = (*env)->GetFieldID(env,对象所属的类的jclass,
属性名,
属性对应的属性描述符号);
2.(*env)->GetObjectField(env,对象,属性id);
访问静态属性:
假如有个类如下:
class StaticFielcdAccess {
private static int si;
private native void accessField();
}
那么实现为:
JNIEXPORT void JNICALL
Java_StaticFieldAccess_accessField(JNIEnv *env, jobject obj)
{
jfieldID fid; /* store the field ID */
jint si;
jclass cls = (*env)->GetObjectClass(env, obj); //获取类class
fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); //获取静态属性id
si = (*env)->GetStaticIntField(env, cls, fid); //读去属性的值
(*env)->SetStaticIntField(env, cls, fid, 200); //设置静态属性的值
}
通过jni怎么去调用java层的类的实例方法和静态方法呢?
**************************1.访问实例方法**************************
假如有个这样的类:
class InstanceMethodCall {
private native void nativeMethod();
private void callback() {
System.out.println("In Java");
}
public static void main(String args[]) {
InstanceMethodCall c = new InstanceMethodCall();
c.nativeMethod();
} static {
System.loadLibrary("InstanceMethodCall");
}
}
jni实现:
JNIEXPORT void JNICALL
Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
//1.拿到class
jclass cls = (*env)->GetObjectClass(env, obj);
//2.拿到方法id
jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
//3.根据obj,和方法id 调用方法
(*env)->CallVoidMethod(env, obj, mid);
}
根据方法的返回值来决定调用哪个方法:
Call<Type>Method
如果返回int 那么最后一步就调用 (*env)->CallIntMethod(env,obj,mid);
最后那个参数 "()V" 是方法描述符:
(I)V 带一个int 类型的参数,返回值类型为void
()D 没有参数,返回double //注意!!没有参数并不是 (V)D
方法public static void main(String[] args) 对应的方法描的符为:
([Ljava/lang/String;)V
完整的方法描述符规则,http://java.sun.com/docs/books/jni/ 12.3.4章节
**************************2.访问静态方法**************************
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid =
(*env)->GetStaticMethodID(env, cls, "callback", "()V");
(*env)->CallStaticVoidMethod(env, cls, mid); //注意,这里跟访问实例方法的区别是 第二个参数不是obj,而是cls
**************************3.访问父类的方法,怎么搞?**************************
传当前调用对象obj,父类class,方法id
CallNonvirtualVoidMethod,
**************************4.怎么用jni API 来调用 java层的构造器?**************************
我们来看在linphone中它是怎么调用Android 里面的AudioRecord类的构造器的->
查看android API
http://developer.android.com/reference/android/media/AudioRecord.html
AudioRecord的构造器声明为:
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
在linphone源码库的submodules/linphone/mediastreamer2/src/msandroid.cpp的方法sound_read_setup中有这么一段代码:
static void sound_read_setup(MSFilter *f){
//...
jmethodID constructor_id=0;
//...
JNIEnv *jni_env = ms_get_jni_env();
//这里是拿到类AudioRecord对应的class
d->audio_record_class = (jclass)jni_env->NewGlobalRef(jni_env->FindClass("android/ media/AudioRecord"));
//构造方法毕竟还是构造方法,所以,思路肯定是要先拿到构造方法对应的methodId
//调用构造方法时,按调用实例方法的形式来调,只是第二个参数不再是构造方面名,而是<init>
//因为类AudioRecord的构造方法有5个int类型参数,所以第三个参数 为 (IIIII)V
constructor_id = jni_env->GetMethodID(d->audio_record_class,"<init>", "(IIIII)V");
//构造方法的methodId 拿到了那就可以创建对象了:
d->audio_record = jni_env->NewObject(d->audio_record_class
,constructor_id
,1/*MIC*/
,d->rate
,2/*CHANNEL_CONFIGURATION_MONO*/
,2/* ENCODING_PCM_16BIT */
,d->buff_size);