一、前言
Android进行JNI开发时,有可能需要传递自定义的Java对象,这里包括从Java层传到Natvie层,以及从Native层传到Java层,本文将分别对这两种场景做简单的介绍。
二、 先定义一个Java对象
public class Book {
private String title;
private int year;
private float price;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
}
三、把对象从Java层传到Native层
先上一个表,后面会用到
Java 类型 | 字段符号 |
---|---|
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | L |
float | F |
double | D |
void | V |
String | Ljava/lang/String; |
Native层代码:
#include <jni.h>
#include <string>
#include<android/log.h>
#define TAG "NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
//从Java层传递Book对象到Native
extern "C" JNIEXPORT void JNICALL
Java_com_jack_jnidemo_MainActivity_java2Native (
JNIEnv* env,
jobject object,
jobject book) {
jclass booCls = env->GetObjectClass(book); //获得java对象的引用
if(booCls == NULL) {
LOGD("book is null");
}
//env->GetFieldID,该方法能获取到对象字段的引用,最后一个参数参见上表
jfieldID titleField = env->GetFieldID(booCls,"title","Ljava/lang/String;");
jfieldID yearField = env->GetFieldID(booCls, "year","I");
jfieldID priceField = env->GetFieldID(booCls, "price","F");
//env->GetIntField得到字段对应的值
jstring title = (jstring)env->GetObjectField(book titleField);
jint year = env->GetIntField(book, yearField);
jfloat price = env->GetFloatField(book, priceField);
const char * c_title = env->GetStringUTFChars(title, NULL);
LOGD("书名:%s", c_title);
LOGD("出版年份:%d", year);
LOGD("价格:%f",price);
env->ReleaseStringUTFChars(title,c_title);
}
Java层简单定义一下Native方法就可以直接调用:
public native void java2Native(Book book);
四、把一个对象从Native传到java层
先上Native层代码:
//把一个对象从Native传到java层
extern "C" JNIEXPORT jobject JNICALL
Java_com_jack_jnidemo_MainActivity_native2Java(
JNIEnv* env,
jobject object) {
jclass booCls = env->FindClass("com/jack/jnidemo/Book"); //获得Book类的引用
if(booCls == NULL){
LOGD("book is null");
}
//构造函数
jmethodID constrocID = env->GetMethodID(booCls,"<init>","()V");
//利用构造函数生成一个对象
jobject bookObj = env->NewObject(booCls,constrocID);
//先拿到字段,准备赋值
jfieldID titleField = env->GetFieldID(booCls,"title","Ljava/lang/String;");
jfieldID yearField = env->GetFieldID(booCls,"year","I");
jfieldID priceField = env->GetFieldID(booCls,"price","F");
//赋值
jstring cTitle = env->NewStringUTF("来自Native层");
env->SetObjectField(bookObj, titleField, cTitle);
jint year = 2018;
env->SetIntField(bookObj, yearField, year);
jfloat pricce = 35.5;
env->SetFloatField(bookObj, priceField, pricce);
return bookObj;
}
Java层简单定义一下Native方法就可以直接调用:
public native Book native2Java();
五、总结
可以看出,JNI传递自定义对象并不复杂,上面的代码基本能满足日常开发需求。
网友评论