首页 > 代码库 > jni.h头文件详解(二)
jni.h头文件详解(二)
一:struct JNINativeInterface_{}
结构体的作用:它有点像我们char字符驱动的 file_ops结构体,它定义各种函数对在(jni.h头文件详解一)中定义的各种数据的操作函数集体.
二:它包含那些针对Java中类和对象的相关操作呢如下图.
三:下面我们讲详细介绍14个部分方法的用法和解析
3.1.版本信息操作函数.
一.GetVersion
jint (JNICALL *GetVersion)(JNIEnv *env)
--模块信息:该模块主要针对的JNI接口的版本信息操作函数.
函数原型:jint (JNICALL *GetVersion)(JNIEnv *env)
描 述:它用来返回jni的版本信息.version = (*env)->GetVersion(env);
我们通过这个方法获取版本信息.并通过回调java的getVersion()方法显示版本号.
参 数:这个JNIEnv是JNI的运行环境.这个环境中包含了上图的14大块的操作函数等等.
返回值:返回一个0-65535大小的数.他是一个16位的正整数.高八位是主版本号.低八位是次版本号.
例 程:
--1.1 函数使用Demo流程介绍.
通过Java对象的构造方法,把当前对象传递到C中.C获取到该对象之后,保存Java对象的引用,并获取相应的方法等.
获取该对象之后,C会调用获取JNI版本的函数.获取版本号,并调用Java层的getVersion()函数,将版本号显示出来.如图:
--1.2 代码
package com.octopus.test03; import android.os.Bundle; import android.app.Activity; import android.graphics.Color; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; public class Act1 extends Activity implements OnClickListener { private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private Button btn, btn3; public static Act1 ref; public TextView tv; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); ref = this; LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); btn = new Button(this); btn.setId(101); btn.setText("run(Adder)"); btn.setBackgroundResource(R.drawable.ic_launcher); btn.setOnClickListener(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(120, 50); param.topMargin = 10; layout.addView(btn, param); btn3 = new Button(this); btn3.setId(103); btn3.setText("exit"); btn3.setBackgroundResource(R.drawable.ic_launcher); btn3.setOnClickListener(this); layout.addView(btn3, param); tv = new TextView(this); tv.setTextColor(Color.WHITE); tv.setText(""); LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10; layout.addView(tv, param2); setContentView(layout); } public void onClick(View v) { if (v == btn) { int a = 1, b = 1; GetVersion adder = new GetVersion(); } else if (v == btn3) { finish(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
--1.3 Jni层代码
package com.octopus.test03; import java.lang.ref.WeakReference; import android.os.Handler; import android.os.Message; public class GetVersion { private static Handler h; static { System.loadLibrary("HelloNdk"); } public GetVersion() { h = new Handler() { public void handleMessage(Message msg) { Act1.ref.setTitle(msg.obj.toString()); } }; nativeSetup(new WeakReference<GetVersion>(this)); } private static void getVersion(Object version_ref, int what,int message) { String obj1 = "Jni Version is : "+ message; Message m = h.obtainMessage(what, obj1); h.sendMessage(m); } private native void nativeSetup(Object weak_this); }
--1.4 C 层代码
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include "com_octopus_test03_GetVersion.h" 3 /* Header for class com_octopus_test03_GetVersion */ 4 5 /* 6 * Class: com_octopus_test03_GetVersion 7 * Method: nativeSetup 8 * Signature: (Ljava/lang/Object;)V 9 */ 10 11 jclass mClass; 12 jobject mObject; 13 jmethodID mid; 14 15 JNIEXPORT void JNICALL Java_com_octopus_test03_GetVersion_nativeSetup 16 (JNIEnv *env, jobject this, jobject weak_this) 17 { 18 jint version =0; 19 jclass class = (*env)->GetObjectClass(env,this); 20 mClass = (jclass)(*env)->NewGlobalRef(env,class); 21 mObject = (*env)->NewGlobalRef(env,weak_this); 22 mid = (*env)->GetStaticMethodID(env, mClass,"getVersion","(Ljava/lang/Object;II)V"); 23 24 version = (*env)->GetVersion(env); //我们通过这个方法获取版本信息.并通过回调java的getVersion()方法显示版本号. 25 (*env)->CallStaticVoidMethod(env,mClass,mid,mObject,1,version); 26 return ; 27 }
1.5.Android.mk文件如下:
SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := HelloNdk LOCAL_SRC_FILES := com_octopus_test03_GetVersion.c include $(BUILD_SHARED_LIBRARY)
--1.6 测试当前JNI的版本为65542
.
转载请说明出处: http://blog.csdn.net/shaohuazuo/
.
3.2. 类模块相关操作.
(DefineClass,FindClass)
jclass (JNICALL *DefineClass) (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len);
jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);
--模块信息:这个模块主要是C或者C++中如何获取Java的Class类对象. 这个接口再Android上没有得到支持.
一:DefineClass
函数原型:jclass (JNICALL *DefineClass) (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len);
描 述: 从二进制的.class的数据缓冲区中加载类.
参 数: env java本地接口指针.
name 需要加载类的简短名称.比如下载需要加载一个com/zuoshaohua/Test.java这个类,那么该名称就是 Test
loader 类加载器对象.该类用来加载java字节码.class文件
buf 这个是字节码缓冲区数组.
len 该数组的长度.
返回值:
返回一个jclass类型的结构体.他对应的是Java中的类相关信息.
例 程:
--1.1 相关的java背景知识说.可以参考http://blog.csdn.net/lovingprince/article/details/4317069博客,
Java类加载器.也就是我们的loader参数的详细介绍.
在这里我们简单的说说loader的作用.在Java语言中loader是一个将 .class文件加载到内存的一个类加载器.
--1.2 例程的业务逻辑介绍:
写一个测试的java类.他用来输出一个字符串..我们把他编译成一个.class文件.然后使用DefineClass进行加载.
并再Activity中输出该字符串.
--1.3代码 (注释 界面代码和上一个实例是一样的.)
package com.octopus.test03; import java.lang.ref.WeakReference; import android.os.Handler; import android.os.Message; public class DefindClassTest { ClassLoader loader; private static Handler h; static { System.loadLibrary("HelloNdk"); } public DefindClassTest() { h = new Handler() { public void handleMessage(Message msg) { Act1.ref.setTitle(msg.obj.toString()); } }; loader = DefindClassTest.class.getClassLoader(); if(loader==null){ System.out.println("loader error\n"); } //将获得的类加载器,传入到C层. nativeSetup(new WeakReference<ClassLoader>(loader)); } private static void getVersion(Object version_ref, Object test, int what,int message) { String obj1 = "Jni Version is : "+ message+ "C Create obj is"+ test; Message m = h.obtainMessage(what, obj1); h.sendMessage(m); } private native void nativeSetup(Object weak_this); }
--1.4 jni中c端实现代码
/* DO NOT EDIT THIS FILE - it is machine generated */ #include "com_octopus_test03_DefindClassTest.h" #include <stdlib.h> #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /* * Class: com_octopus_test03_DefindClassTest * Method: nativeSetup * Signature: (Ljava/lang/Object;)V */ /* jclass (JNICALL *DefineClass) (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,jsize len); */ jclass mClass; jobject mObject; jmethodID mid; JNIEXPORT void JNICALL Java_com_octopus_test03_DefindClassTest_nativeSetup (JNIEnv *env, jobject this, jobject weak_this){ int fd; off_t len; jint ret; int pos; off_t tmplen; jbyte *buf = NULL; jclass testclass; jint version =0; jobject mOjbect1; jobject obj1; jclass class = (*env)->GetObjectClass(env,this); mClass = (jclass)(*env)->NewGlobalRef(env,class); //我们需要获取到DefineClassTest该类的类加载器. mObject = (*env)->NewGlobalRef(env,weak_this); //使用c读取我们需要加载的文件. fd = open("/system/Test.class",O_RDONLY); len = lseek(fd, 0, SEEK_END); buf = calloc(len,1); if(buf == NULL){ printf("calloc error \n"); return; } lseek(fd, 0,SEEK_SET); pos = 0; tmplen = len; while(tmplen > 0){ ret += read(fd,buf+ret,tmplen-ret); pos +=ret; tmplen -=ret; } close(fd); //使用DefineClass函数加载这个类 testclass = (*env)->DefineClass(env,"Test",mObject,buf,len); if(testclass == NULL) { return; } free(buf); obj1 = (*env)->AllocObject(env,testclass); //生成一个对象,并调用该对象的方法. mid = (*env)->GetStaticMethodID(env, mClass,"getVersion","(Ljava/lang/Object;Ljava/lang/Object;II)V"); version = (*env)->GetVersion(env); (*env)->CallStaticVoidMethod(env,mClass,mid,this,obj1,1,version); return ; }
二: FindClass
函数原型:jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);
描 述: 该函数用于加载本地定义的类。它将搜索由CLASSPATH 环境变量为具有指定名称的类所指定的目录和 zip 文件。
该CLASSPATH一般为:
#set java environment
JAVA_HOME=/home/xxx/java/jdk1.6.0_12
export JRE_HOME=/home/xxx/java/jdk1.6.0_12/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
findClass函数的java背景知识在我的博客由介绍:
参 数: env java本地接口指针.
name 需要加载类的简短名称.比如下载需要加载一个com/zuoshaohua/Test.java这个类,该参数就是 "com/zuoshaohua/Test"
返回值:
返回一个jclass类型的结构体.他对应的是Java中的类相关信息.它是类的字节码对象.
例 程:
--2.1 流程:
1.MainActivity的onCreate()方法中初始化一个ManPerson.
2.在ManPerson的构造函数最后我们会调用nativeSetup把ManPerson对象传递到C中.
3.我们会再C中得到ManPerson的属性Id信息,并保存起来.并使用findClass()方法获取Person类字节码对象,并生成Person对象的全集引用.
4.当我们点击应用层的btn时,C会获取ManPerson的信息.使用bean的setXxx()给Person对象赋值.并返回给对象到java层.
--2.2类图:
--2.3 Activity代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/personView"
android:layout_width="260dp"
android:layout_height="100dp"
android:layout_alignParentTop="true"
android:layout_marginTop="28dp" />
<Button
android:id="@+id/exit"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignBaseline="@+id/run"
android:layout_alignBottom="@+id/run"
android:layout_marginLeft="30dp"
android:layout_toRightOf="@+id/run"
android:text="EXIT" />
<Button
android:id="@+id/run"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignLeft="@+id/personView"
android:layout_below="@+id/personView"
android:layout_marginLeft="31dp"
android:layout_marginTop="22dp"
android:text="RUN" />
</RelativeLayout>
package com.zuoshaohua;
import com.zuoshaohua.ndk.ManPerson;
import com.zuoshaohua.ndk.NativeExec;
import com.zuoshaohua.ndk.Person;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
private Button runbtn;
private Button exitbtn;
private ManPerson manPerson;
private TextView personView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
exitbtn = (Button) this.findViewById(R.id.exit);
runbtn = (Button) this.findViewById(R.id.run);
personView = (TextView) this.findViewById(R.id.personView);
manPerson = new ManPerson("zuoshaohua",33,"男");
runbtn.setOnClickListener(MainActivity.this);
exitbtn.setOnClickListener(this);
}
@Override
public void onClick(View arg0) {
int id = arg0.getId();
switch (id) {
case R.id.run:
Person p = (Person)NativeExec.nativeExec(); //获取c代码生成对象.
personView.setText("name ="+ p.getName()+ "age="+p.getAge()+"gender="+p.getGender()); //输出这个对象的值.
break;
case R.id.exit:
this.finish();
break;
default:
this.finish();
break;
}
}
}
--2.4 jni代码
package com.zuoshaohua.ndk; public class ManPerson { private String name; private int age; private String gender; static { System.loadLibrary("HelloNdk"); //加载动态库文件. } public ManPerson(String name, int age, String gender){ this.name = name; this.age = age; this.gender =gender; nativeSetup(); } private native void nativeSetup(); }
package com.zuoshaohua.ndk; public class NativeExec { public static native Object nativeExec(); }
package com.zuoshaohua.ndk; public class Person { private String name; private int age; private String gender; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } }
--2.5 c层代码
#include "com_zuoshaohua_ndk_ManPerson.h" #include "com_zuoshaohua_ndk_NativeExec.h" /* * Class: com_zuoshaohua_ndk_ManPerson * Method: nativeSetup * Signature: ()V */ jobject m_obj, p_obj; jfieldID name_id,age_id,gender_id; jmethodID pname_mid,page_mid,pgender_mid; JNIEXPORT void JNICALL Java_com_zuoshaohua_ndk_ManPerson_nativeSetup (JNIEnv *env, jobject this) { #if 1 jclass clz = (*env)->GetObjectClass(env,this); //通过ManPerson的对象获取ManPerson字节码对象. m_obj = (*env)->NewGlobalRef(env,this); //将这个对象设置为全局引用. name_id = (*env)->GetFieldID(env,clz,"name","Ljava/lang/Object;"); //获取ManPerson对象的属性. age_id = (*env)->GetFieldID(env,clz,"age","I"); gender_id = (*env)->GetFieldID(env,clz,"gender","Ljava/lang/Object;"); jclass personclz = (*env)->FindClass(env,"com/zuoshaohua/ndk/Person"); //通过FindClass方法获取Person类的字节码对象. jmethodID constr =(*env)->GetMethodID(env,personclz,"<init>", "()V"); //获取这个对象无参的构造函数. jobject ref = (*env)->NewObject(env,personclz,constr); //生成Person对象. p_obj = (*env)->NewGlobalRef(env, ref); //将Person对象设置为全局引用. pname_mid = (*env)->GetMethodID(env,personclz,"setName","(Ljava/lang/Object;)V"); //获取Person的Setxxx()方法的ID. page_mid = (*env)->GetMethodID(env,personclz,"setAge", "(I)V"); pgender_mid = (*env)->GetMethodID(env,personclz,"setGender","(Ljava/lang/Object;)V"); #endif } /* * Class: com_zuoshaohua_ndk_NativeExec * Method: nativeExec * Signature: ()Ljava/lang/Object; */ JNIEXPORT jobject JNICALL Java_com_zuoshaohua_ndk_NativeExec_nativeExec (JNIEnv *env, jclass this) { #if 1 jint age = 0; jstring name,gender; name = (*env)->GetObjectField(env,m_obj,name_id); //获取ManPerson属性的值. gender = (*env)->GetObjectField(env,m_obj,gender_id); age = (*env)->GetIntField(env,m_obj,age_id); (*env)->CallVoidMethod(env, p_obj,pname_mid,name); //调用Person的Setxxx()方法给Person对象赋值. (*env)->CallVoidMethod(env, p_obj,page_mid,age); (*env)->CallVoidMethod(env, p_obj,pgender_mid,gender); //(*env)->SetIntField(env,p_obj,age_id,10); //返回Person对象. return p_obj; #endif }
转载请注明出处: http://blog.csdn.net/shaohuazuo/article/details/42932813
3.3 java反射相关模块
jmethodID (JNICALL *FromReflectedMethod)(JNIEnv *env, jobject method);
jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);
jobject (JNICALL *ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);
jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);
函数背景知识介绍: 请看博客(Java反射机制)
java.lang.reflect:
提供类和接口,以获得关于类和对象的反射信息。在安全限制内,
反射允许编程访问关于加载类的字段、方法和构造方法的信息,
并允许使用反射字段、方法和构造方法对其底层对等项进行操作。
更多相关知识可以参考http://www.javaweb.cc/help/JavaAPI1.6/
也可以进入博客:?????????????
一:FromReflectedMethod
函数原型: jmethodID (JNICALL *FromReflectedMethod)(JNIEnv *env, jobject method);
描 述: 通过java.lang.reflect中Method类的对象获取一个函数的MethodID. 就可以调用Java中某个方法.
参 数: env java native interface porint,(java本地接口指针)
method 这个是jva.lang.reflect.Method对象.
要获取Method对象第一步.需要获取Class对象.再通过Class对象获取Method.
1.获取Class对象的三种方法是:
1.2) 对象.getClass(),例如,Class pclass = new Person().getClass()
1.3) Class.forName(“类名”),例如,Class pclass = Class.forName(“com.zuoshaohua.Person”);
2.获取Method对象,详细方法介绍可以参考http://www.javaweb.cc/help/JavaAPI1.6/手册
2.1)Class.getMethods(),
2.2)Class.getMethod(String, Class[]),
2.3)Class.getDeclaredMethods(),
2.4)Class.getDeclaredMethod(String, Class[])
1.5) ToReflectedMethod()通过C中的JNI标准获取Methdod对象. 返回值:返回一个方法的MethodID指针.
二:FromReflectedField
函数原型: jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);
描 述:通过java.lang.reflect中Field类的对象获取字段对象.可以获取这个字段的jfieldID了.
参 数: env java native interface porint,(java本地接口指针)
field Field对象,这个对象主要用来描述java中的字段信息.通过这个类对象.我们可以获得
这个字段的名称,类型等等信息.
1.获取这个对象由如下5种方法:
1.1)Class.getDeclaredField(String name);
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
1.2)Class.getDeclaredFields();
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
1.3)Class.getField(String name);
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
1.4)Class.getField();
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
1.6)ToReflectedFile()
通过C中JNI标准中提供的上面的函数,也可以获取Field对象.
返回值:返回一个字段的jfieldID指针.
三:ToReflectedMethod
函数原型: jobject (JNICALL *ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);
描 述: 这个方法是通过方法的methodId返回一个java.lang.reflect.Method对象,是FromReflectedMethod的反操作.
参 数: env java native interface porint,(java本地接口指针)
cls 该方法的类对象.可以通过FindClass()获取.如果知道对象的话可以使用GetObjectClass()来获取这个jclass对象.
methodID 这个对象是jmethodID指针.可以通过GetMethodID方法获取.
isStatic 该方法是不是静态的,JNI标准中提供了两个宏表示.JNI_FALSE,和JNI_TRUE.
返回值:返回一个Method对象.也就是说再FromReflectedMethod 中多了一种方法可以获取Method对象的方法.
四:ToReflectedField
函数原型: jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);
描 述: 通过filedID可以返回一个java.lang.reflect.Field对象.
参 数: env java native interface porint,(java本地接口指针)
cls 该方法的类对象.可以通过FindClass()获取.如果知道对象的话可以使用GetObjectClass()来获取这个jclass对象.
methodID 这个对象是jField指针.可以通过GetFieldID方法获取.
isStatic 该方法是不是静态的,JNI标准中提供了两个宏表示.JNI_FALSE,和JNI_TRUE.
返回值: 返回一个Field对象.
五:例程
1.1 流程
1. 定义一个Person类.这个Person类三个属性.name, age, gender.还有getxxx()和setxxx()方法.
2. 定义一个Android的界面.它的MainActivity类关联了一个Person对象.也就是,Person类是Activity的一个属性.
3. 在MainActivity中,静态初始化这个Person对象.我们使用该静态对象.p.getClass()获取类Class对象clz.
4. 我们需要获取这个Class中的Method对象和Field对象.clz.getMethod(); clz.getField对象.
通过 ReflectMethodDeom本地方法和ReflectFieldDemo本地方法传入到C层.
5. c通过这两个对象获取到对象的jfieldID对象和jmethodID.并进行相应的操作.
1.2 类图
1.3 代码
1. MainActivity代码
package com.zuoshaohua.reflect; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { private static Person p = new Person("zuoshaohua",33,"男"); private Button runBtn; private Button exitBtn; TextView textView; static { System.loadLibrary("reflect"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); runBtn = (Button)this.findViewById(R.id.run); exitBtn = (Button)this.findViewById(R.id.exit); textView = (TextView)this.findViewById(R.id.personView); this.runBtn.setOnClickListener(this); this.exitBtn.setOnClickListener(this); } private void refelectTest(){ Class<? extends Person> c = p.getClass(); try { StringBuffer sb = new StringBuffer(); Method method = c.getMethod("setAge", int.class); //Field field = c.getField("age"); Field field = c.getDeclaredField("age"); sb.append("oldName ="+p.getName()+"oldAge="+p.getAge()+ "oldGender="+p.getGender()+"\n"); Field field1 = ReflectFieldDemo(p,field); //调用本地方法.将描述age字段的Field对象传进去. //field1.set(p, "shaohuazuo"); Method m1 = ReflectMethodDemo(p,method); //调用本地方法.将描述setAge()方法的Method对象传入到C层代码. sb.append("oldName1 ="+p.getName()+"oldAge1="+p.getAge()+ "oldGender1="+p.getGender()+"\n"); Object args[] = new Object[1]; args[0] = new String("shaohuazuo"); m1.invoke(p, args); //调用返回的方法. field1.setAccessible(true); String name =(String)field1.get(p); sb.append("newName ="+name+"newAge="+p.getAge()+"newGender="+p.getGender()); textView.setText(sb.toString()); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } private static native Field ReflectFieldDemo(Person p,Field f); private static native Method ReflectMethodDemo(Person p, Method m); @Override public void onClick(View arg0) { // TODO Auto-generated method stub switch(arg0.getId()) { case R.id.run: refelectTest(); break; case R.id.exit: this.finish(); break; default: this.finish(); break; } } }
2. Person.java代码
package com.zuoshaohua.reflect; public class Person { private String name; private int age; private String gender; public Person(String string, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } }
3. 生成.h头文件.
zshh@HP:~/work/android/jni/Reflect/jni$
javah -o reflect.h -classpath ../bin/classes com.zuoshaohua.reflect.MainActivity
4. reflect.h代码
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_zuoshaohua_reflect_MainActivity */ #ifndef _Included_com_zuoshaohua_reflect_MainActivity #define _Included_com_zuoshaohua_reflect_MainActivity #ifdef __cplusplus extern "C" { #endif /* * Class: com_zuoshaohua_reflect_MainActivity * Method: ReflectFieldDemo * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field; */ JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectFieldDemo (JNIEnv *, jclass, jobject, jobject); /* * Class: com_zuoshaohua_reflect_MainActivity * Method: ReflectMethodDemo * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method; */ JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectMethodDemo (JNIEnv *, jclass, jobject, jobject); #ifdef __cplusplus } #endif #endif
5. reflect.c代码
#include "reflect.h" #include <android/log.h> #include <stdio.h> #if 0 jmethodID (JNICALL *FromReflectedMethod) (JNIEnv *env, jobject method); jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field); jobject (JNICALL *ToReflectedMethod) (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); #endif jclass clazz; /* * Class: com_zuoshaohua_reflect_MainActivity * Method: ReflectFieldDemo * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field; */ JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectFieldDemo (JNIEnv * env, jclass this, jobject pthis, jobject fthis) { jint age =0; jclass clz =(*env)->GetObjectClass(env,pthis); //通过Person对象获取他的Class对象信息,从而得到一个jclass对象. jfieldID age_id = (*env)->FromReflectedField(env,fthis); //通过Field对象获取Person属性的jfieldID指针. age = (*env)->GetIntField(env,pthis,age_id); //通过这个对象和age_id获取这个属性的值. __android_log_print(ANDROID_LOG_INFO, "ReFlectFieldDemo", "age: %d", age); jfieldID name_id = (*env)->GetFieldID(env,clz,"name","Ljava/lang/String;"); //获取name字段的jfieldID. __android_log_print(ANDROID_LOG_INFO, "ReFlectFieldDemo", "end!!!!!"); return (*env)->ToReflectedField(env,clz,name_id,JNI_FALSE); //通过jfieldID生成一个Java的Field对象.并返回. } /* * Class: com_zuoshaohua_reflect_MainActivity * Method: ReflectMethodDemo * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method; */ JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectMethodDemo (JNIEnv *env , jclass this, jobject pthis, jobject mthis) { //我们使用mthis.来获取jmethodID指针.并通过该指针调用到set方法.来改变Person属性的值. jclass pclazz = (*env)->GetObjectClass(env,pthis); jmethodID setAgeId = (*env)->FromReflectedMethod(env,mthis); (*env) ->CallVoidMethod(env,pthis,setAgeId,100); __android_log_print(ANDROID_LOG_INFO,"ReflectMethodDemo","is callVoidMethod Done!!!!\n"); jmethodID setName_id = (*env)->GetMethodID(env,pclazz,"setName","(Ljava/lang/String;)V"); return (*env)->ToReflectedMethod(env, pclazz,setName_id, JNI_FALSE); }
6. Android.mk代码
SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := reflect LOCAL_SRC_FILES := reflect.c LOCAL_LDLIBS := -llog #LOCAL_SHARED_LIBRARIES :=libc include $(BUILD_SHARED_LIBRARY)
1.4 测试结果
转载请注明出处: http://blog.csdn.net/shaohuazuo/article/details/42932813
jni.h头文件详解(二)