您的位置:首页 > 移动开发 > Android开发

Android NDK开发之JNI调用Java对象

2015-11-28 09:48 483 查看
         通过使用合适的JNI函数,你可以创建Java对象,get、set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数。JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。
       下面列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldID或jmethodID。

1、得到一个对象实例的成员变量的ID

jfieldID  GetFieldID(JNIEnv*env, jclass thiz, const char* fieldName, const char* fieldType);
    其中第三个参数是所要获取的成员变量名称,第四个参数是该成员变量的类型。

2、得到一个静态的成员变量的ID

jfieldID    GetStaticFieldID(JNIEnv*env, jclass thiz, const char* fieldName, const char* fieldType);
    其中第三个参数是所要获取的成员变量名称,第四个参数是该成员变量的类型。

3、得到一个对象实例的方法的ID

jmethodID GetMethodID(JNIEnv* env, jclass thiz, const char* methodName, const char* methodSign);
   其中第三个参数是所要获取的成员函数名称,第四个参数是该成员函数的签名。实例对象的成员函数的签名与函数的参数类型,返回值类型一一对应的。

"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();

"(II)V" 表示 void Func(int, int);

那其他情况呢?请查看下表:
类型符号
booleanZ
byteB
charC
shortS
intI
longL
floatF
doubleD
voidV
object对象LClassName;      L类名;
Arrays[array-type        [数组类型
methods方法(argument-types)return-type     (参数类型)返回类型
稍稍补充一下:

1、方法参数或者返回值为java中的对象时,签名中必须以“L”加上其路径,不过此路径必须以“/”分开,自定义的对象也使用本规则

比如说 java.lang.String为“java/lang/String”,com.nedu.jni.helloword.Student为"Lcom /nedu/jni/helloword/Student;"

2、方法参数或者返回值为数组类型时,请前加上[

例如[I表示 int[],[[[D表示 double[][][],即几维数组就加几个[
4、得到一个静态方法的ID
jmethodID GetStaticMethodID(JNIEnv* env, jclass thiz, const char* methodName, const char* methodSign);
其中第三个参数是所要获取的成员函数名称,第四个参数是该成员函数的签名。

5、例子

//Person.java
package com.igood.ndk.hello;
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//int类型的静态成员变量
public static int mIntStaticField = 100;
//String类型的静态成员变量
public static String mStringStaticField = "I am a static String";

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 static int setmIntStaticField(int IntStaticField,String StringStaticField) {
Person.mIntStaticField = IntStaticField;
Person.mStringStaticField = StringStaticField;
return 0;
}
}

//NativeClass.java
package com.igood.ndk.hello;
import java.util.List;
public class NativeClass {
//静态代码块在类加载时会执行,这个时候就会加载本地的C库文件
static{
//加载本地的C库文件
System.loadLibrary("helloAndroidNDK");
}
//声明加载的C库中的本地方法
public native List<Person> testObject();
}

//com_igood_ndk_hello_NativeClass.h
#include <jni.h>

#ifndef _Included_com_igood_ndk_hello_NativeClass
#define _Included_com_igood_ndk_hello_NativeClass
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_igood_ndk_hello_NativeClass
* Method: testObject
* Signature: ()Ljava/util/List;
*/
JNIEXPORT jobject JNICALL Java_com_igood_ndk_hello_NativeClass_testObject
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

//com_igood_ndk_hello_NativeClass.c
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include "com_igood_ndk_hello_NativeClass.h"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "helloNDK", __VA_ARGS__))

JNIEXPORT jobject JNICALL Java_com_igood_ndk_hello_NativeClass_testObject
(JNIEnv *env, jobject thiz)
{
/* 查找指定名称类 */
jobject jPerson = (*env)->FindClass(env, "com/igood/ndk/hello/Person");//获得Person类引用

//默认构造函数,不传参数
jmethodID construction_id = (*env)->GetMethodID(env, jPerson,"<init>", "()V");
//通过NewObject来创建对象
jobject mPersonObj = (*env)->NewObject(env, jPerson,construction_id);
/*
获取方法id
(Ljava/lang/String)表示此方法参数为java.lang.String。返回值为V,表示无返回值;
*/
jmethodID jsetName = (*env)->GetMethodID(env, jPerson, "setName", "(Ljava/lang/String;)V");
if(jsetName == NULL)
{
LOGI("method setName ID not found");
return -1; //如果方法ID没有找到
}
jstring str1 = (*env)->NewStringUTF(env, "I am Native setName");

/*
调用此实例方法,最后一个参数为可变参数,对应值为
方法的参数列表。
*/

(*env)->CallVoidMethod(env,mPersonObj,jsetName,str1);

jfieldID m_name = (*env)->GetFieldID(env, jPerson,"name","Ljava/lang/String;");
if(m_name == NULL)
{
LOGI("variable name ID not found");
return -1; //如果成员变量ID没有找到
}

jstring javaNameStr = (jstring)(*env)->GetObjectField(env, mPersonObj ,m_name); // 获得该属性的值
const char * c_javaName = (*env)->GetStringUTFChars(env, javaNameStr , NULL); //转换为 char *类型
LOGI("the name from java is %s",c_javaName); //输出显示
(*env)->ReleaseStringUTFChars(env, javaNameStr , c_javaName); //释放局部引用

//构造一个jString对象
char * c_ptr_name = "I come from Native" ;
jstring cName = (*env)->NewStringUTF(env, c_ptr_name); //构造一个jstring对象
(*env)->SetObjectField(env, mPersonObj ,m_name, cName); // 设置该字段的值
//获取int类型成员变量
jfieldID m_age = (*env)->GetFieldID(env, jPerson,"age","I");
if(m_age == NULL)
{
LOGI("variable age ID not found");
return -1; //如果成员变量ID没有找到
}
jint age = 28;

(*env)->SetIntField(env, mPersonObj ,m_age, age); // 设置该字段的值
jint age1 = (*env)->GetIntField(env, mPersonObj ,m_age);
LOGI("get the age from java is %d",age1); //输出显示
//获取静态成员变量
jint m_IntVar = (*env)->GetStaticIntField(env,jPerson, (*env)->GetStaticFieldID(env,jPerson, "mIntStaticField", "I"));
jstring m_StringVar = (*env)->GetStaticObjectField(env,jPerson, (*env)->GetStaticFieldID(env,jPerson, "mStringStaticField", "Ljava/lang/String;"));
if(m_StringVar == NULL)
{
LOGI("static variable ID not found");
return -1; //如果成员变量ID没有找到
}
const char * c_StringVar = (*env)->GetStringUTFChars(env, m_StringVar , NULL); //转换为 char *类型
LOGI("m_IntVar=%d,m_StringVar=%s",m_IntVar,c_StringVar);

jmethodID staticMethodID = (*env)->GetStaticMethodID(env,jPerson,"setmIntStaticField","(ILjava/lang/String;)I");
if(staticMethodID == NULL)
{
LOGI("static Method setmIntStaticField ID not found");
return -1; //如果成员变量ID没有找到
}

jstring parma = (*env)->NewStringUTF(env,"test static method"); //构造一个jstring对象
(*env)->CallStaticIntMethod(env,jPerson,staticMethodID,50,parma);

jclass list_cls = (*env)->FindClass(env,"java/util/ArrayList");//获得ArrayList类引用

if(list_cls == NULL)
{
LOGI("list_cls is null") ;
return -1;
}

jmethodID list_costruct = (*env)->GetMethodID(env,list_cls , "<init>","()V"); //获得得构造函数Id

jobject list_obj = (*env)->NewObject(env,list_cls , list_costruct); //创建一个Arraylist集合对象
//或得Arraylist类中的 add()方法ID,其方法原型为: boolean add(Object object) ;
jmethodID list_add = (*env)->GetMethodID(env,list_cls,"add","(Ljava/lang/Object;)Z");
jmethodID construction_person = (*env)->GetMethodID(env, jPerson,"<init>", "(Ljava/lang/String;I)V");
int i = 0 ;
for(i =0; i < 3 ; i++)
{
jstring str = (*env)->NewStringUTF(env,"Native");
//通过调用该对象的构造函数来new 一个 Person实例
jobject person_obj = (*env)->NewObject(env,jPerson , construction_person ,str, 10+i); //构造一个对象
(*env)->CallBooleanMethod(env,list_obj , list_add , person_obj); //执行Arraylist类实例的add方法,添加一个person对象
}
return list_obj;
}测试例子
//MainActivity.java
package com.igood.ndk.hello;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

NativeClass nc = new NativeClass();
List<Person> persons = nc.testObject();
Log.d("TAG", "mIntStaticField="+ Person.mIntStaticField+" mStringStaticField="+Person.mStringStaticField);
for(int i =0;i<persons.size();i++){
Person p = persons.get(i);
Log.d("TAG", "Name="+ p.getName()+" age="+p.getAge());
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: