作者:左少華 博客:http://blog.csdn.net/shaohuazuo/article/details/42932813 轉載請注明出處:http://blog.csdn.net/shaohuazuo
一: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反射機制)
更多相關知識可以參考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.1) 類名.class,例如 Class pclass = Person.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.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 測試結果