最近在项目中需要android和window之间数据同步,其中window程序是C++写的,生成的一些文件是结构体文件,所以需要能够吧Java对象传给C++生成结构体文件,能够被C++程序识别;同时C++需要把结构体文件读出来传给Java来识别,这里使用了android的NDK开发。
Java层:
public class Student {
public String name;
public long id;
public int age;
public float height;
public float weight;
public double score;
public boolean sex;
public ArrayList<Tpoint> tpoints;
public Student() {
}
public Student(String name, long id, int age, float height, float weight, double score, boolean sex, ArrayList<Tpoint> tpoints) {
this.name = name;
this.id = id;
this.age = age;
this.height = height;
this.weight = weight;
this.score = score;
this.sex = sex;
this.tpoints = tpoints;
}
...
//省略get,set方法
...
}
这里的Student类里包含Tpoint对象集合(这里Tpoint可以理解为X,Y坐标)
public class Tpoint {
public float x;
public float y;
public Tpoint() {
}
public Tpoint(float x, float y) {
this.x = x;
this.y = y;
}
...
//省略get,set方法
...
}
MainActivity主要代码段:
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList<Tpoint> tpoints = initTpoints();
Student student = new Student();
student.setName("小米");
student.setAge(10);
student.setHeight(135.2f);
student.setWeight(45.2f);
student.setId(12345678);
student.setScore(80.5);
student.setSex(false);
student.setTpoints(tpoints);
byte[] data = parseObjectToByteArray(student);
if (data != null) {
Log.d("jokey", "data: " + data.length);
Student stu = parseByteArrayToObject(data);
if (stu != null) {
Log.d("jokey", "stu: " + stu.toString());
}
} else {
Log.d("jokey", "data: null");
}
}
});
private ArrayList<Tpoint> initTpoints() {
ArrayList<Tpoint> tpoints = new ArrayList<>();
tpoints.add(new Tpoint(1, 1));
tpoints.add(new Tpoint(2, 2));
tpoints.add(new Tpoint(3, 3));
tpoints.add(new Tpoint(4, 4));
return tpoints;
}
public native byte[] parseObjectToByteArray(Student student) ;
public native Student parseByteArrayToObject(byte[] data) ;
parseObjectToByteArray(Student student)方法是把Student对象传给Native,返回C++中STUDENT结构体的byte数组
parseByteArrayToObject(byte[] data)方法是parseObjectToByteArray方法的反步骤
Native层:
struct TPOINT {
float x;
float y;
};
struct STUDENT {
char name[50];
long id;
int age;
float height;
float weight;
double score;
bool sex;
TPOINT tpoint[100];
};
这里结构体STUDENT和TOINT对应Java层的Student和Tpoint
#include <jni.h>
#include <string>
#include <iostream>
#include <android/log.h>
#include "Struct.h"//里面是STUDENT和TPOINT结构体
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_com_medlander_candjavaobject_MainActivity_parseObjectToByteArray(JNIEnv *env, jobject thiz,jobject obj_stu) {
jclass stucls = env->GetObjectClass(obj_stu); //或得Student类引用
if (stucls == NULL) {
__android_log_print(ANDROID_LOG_INFO, "jni_jokey", "GetObjectClass obj_stu failed");
}
jfieldID nameFieldID = env->GetFieldID(stucls, "name", "Ljava/lang/String;"); // 获得属性ID
jfieldID idFieldID = env->GetFieldID(stucls, "id", "J"); //获得得Student类的属性id
jfieldID ageFieldID = env->GetFieldID(stucls, "age", "I"); //获得得Student类的属性id
jfieldID heightFieldID = env->GetFieldID(stucls, "height", "F"); //获得得Student类的属性id
jfieldID weightFieldID = env->GetFieldID(stucls, "weight", "F"); //获得得Student类的属性id
jfieldID scoreFieldID = env->GetFieldID(stucls, "score", "D"); //获得得Student类的属性id
jfieldID sexFieldID = env->GetFieldID(stucls, "sex", "Z"); //获得得Student类的属性id
jfieldID tpointFieldID = env->GetFieldID(stucls, "tpoints",
"Ljava/util/ArrayList;"); //获得Student类的ArrayList属性id
jobject tpoints = env->GetObjectField(obj_stu, tpointFieldID);
env->DeleteLocalRef(stucls);
jstring name = (jstring) env->GetObjectField(obj_stu, nameFieldID);//获得属性值
jlong id = env->GetLongField(obj_stu, idFieldID);
jint age = env->GetIntField(obj_stu, ageFieldID); //获得属性值
jfloat height = env->GetFloatField(obj_stu, heightFieldID);
jfloat weight = env->GetFloatField(obj_stu, weightFieldID);
jdouble score = env->GetDoubleField(obj_stu, scoreFieldID);
jboolean sex = env->GetBooleanField(obj_stu, sexFieldID);
const char *c_name = env->GetStringUTFChars(name, NULL);//转换成 char *
STUDENT student;
memset(&student, 0, sizeof(STUDENT));
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "name: %s", c_name);
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "id: %lli", id);
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "age: %d", age);
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "height: %f", height);
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "weight: %f", weight);
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "score: %lf", score);
if (sex)
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "sex: 男");
else
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "sex: 女");
memcpy(student.name, c_name, sizeof(student.name));
//释放引用
env->ReleaseStringUTFChars(name, c_name);
student.id = static_cast<long>(id);
student.age = age;
student.height = height;
student.weight = weight;
student.score = score;
student.sex = sex;
if (tpoints != NULL) {
int i;
jclass cls_arraylist = env->GetObjectClass(tpoints);
jmethodID arraylist_get = env->GetMethodID(cls_arraylist, "get", "(I)Ljava/lang/Object;");
jmethodID arraylist_size = env->GetMethodID(cls_arraylist, "size", "()I");
jint len = env->CallIntMethod(tpoints, arraylist_size);
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "arraylist_size: %d", len);
for (i = 0; i < len; i++) {
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "i: %d", i);
jobject obj_student = env->CallObjectMethod(tpoints, arraylist_get, i);
jclass cls_student = env->GetObjectClass(obj_student);
jfieldID xFieldID = env->GetFieldID(cls_student, "x", "F"); // 获得属性ID
jfieldID yFieldID = env->GetFieldID(cls_student, "y", "F"); // 获得属性ID
jfloat x = env->GetFloatField(obj_student, xFieldID);//获得属性值
jfloat y = env->GetFloatField(obj_student, yFieldID);//获得属性值
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "x: %f", x);
__android_log_print(ANDROID_LOG_DEBUG, "jni_jokey", "y: %f", y);
student.tpoint[i].x = x;
student.tpoint[i].y = y;
env->DeleteLocalRef(obj_student);
env->DeleteLocalRef(cls_student);
}
env->DeleteLocalRef(cls_arraylist);
env->DeleteLocalRef(tpoints);
} else {
__android_log_print(ANDROID_LOG_INFO, "jni_jokey", "GetObjectField tpoints failed");
}
int length = sizeof(STUDENT);
jbyteArray array = env->NewByteArray(length);
env->SetByteArrayRegion(array, 0, sizeof(STUDENT), (jbyte *) &student);
//结束释放
env->ReleaseByteArrayElements(array, env->GetByteArrayElements(array, JNI_FALSE), 0);
return array;
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_medlander_candjavaobject_MainActivity_parseByteArrayToObject(JNIEnv *env, jobject thiz,jbyteArray data) {
jbyte *bBuffer = env->GetByteArrayElements(data, NULL);
char *buf = (char *) bBuffer;
STUDENT student;
memcpy(&student, buf, sizeof(STUDENT));
//释放
env->ReleaseByteArrayElements(data, bBuffer, 0);
//关于包描述符,这儿可以是 com/medlander/candjavaobject/Student 或者是 Lcom/medlander/candjavaobject/Student;
// 这两种类型 都可以获得class引用
jclass stucls = env->FindClass("com/medlander/candjavaobject/Student"); //获得Student类引用
if (stucls == NULL) {
__android_log_print(ANDROID_LOG_INFO, "jni_jokey", "stucls is null");
}
//获得得该类型的构造函数 函数名为 <init> 返回类型必须为 void 即 V
jmethodID constrocMID = env->GetMethodID(stucls, "<init>", "()V");
jobject stu_obj = env->NewObject(stucls, constrocMID); //构造一个对象,调用该类的构造函数,并且传递参数
jfieldID nameFieldID = env->GetFieldID(stucls, "name", "Ljava/lang/String;"); // 获得属性ID
jfieldID idFieldID = env->GetFieldID(stucls, "id", "J"); //获得得Student类的属性id
jfieldID ageFieldID = env->GetFieldID(stucls, "age", "I"); //获得得Student类的属性id
jfieldID heightFieldID = env->GetFieldID(stucls, "height", "F"); //获得得Student类的属性id
jfieldID weightFieldID = env->GetFieldID(stucls, "weight", "F"); //获得得Student类的属性id
jfieldID scoreFieldID = env->GetFieldID(stucls, "score", "D"); //获得得Student类的属性id
jfieldID sexFieldID = env->GetFieldID(stucls, "sex", "Z"); //获得得Student类的属性id
jfieldID tpointFieldID = env->GetFieldID(stucls, "tpoints",
"Ljava/util/ArrayList;"); //获得Student类的ArrayList属性id
// jobject tpoints = env->GetObjectField(stu_ojb, tpointFieldID);
jstring name = env->NewStringUTF(student.name);
env->SetObjectField(stu_obj, nameFieldID, name);
env->SetLongField(stu_obj, idFieldID, student.id);
env->SetIntField(stu_obj, ageFieldID, student.age);
env->SetFloatField(stu_obj, heightFieldID, student.height);
env->SetFloatField(stu_obj, weightFieldID, student.weight);
env->SetDoubleField(stu_obj, scoreFieldID, student.score);
env->SetBooleanField(stu_obj, sexFieldID, static_cast<jboolean>(student.sex));
env->DeleteLocalRef(name);
jclass list_cls = env->FindClass("java/util/ArrayList");
if (list_cls == NULL) {
__android_log_print(ANDROID_LOG_INFO, "jni_jokey", "list_cls is null");
}
jmethodID list_costruct = env->GetMethodID(list_cls, "<init>", "()V"); //获得得构造函数Id
jobject list_obj = env->NewObject(list_cls, list_costruct); //创建一个Arraylist集合对象
//或得Arraylist类中的 add()方法ID,其方法原型为: boolean add(Object object) ;
jmethodID list_add = env->GetMethodID(list_cls, "add", "(Ljava/lang/Object;)Z");
jclass tpoint_cls = env->FindClass("com/medlander/candjavaobject/Tpoint");//获得Student类引用
jmethodID tpoint_costruct = env->GetMethodID(tpoint_cls, "<init>", "(FF)V");
for (int i = 0; i < 4; i++) {
jobject tpoint_obj = env->NewObject(tpoint_cls, tpoint_costruct, student.tpoint[i].x,
student.tpoint[i].y); //构造一个对象
env->CallBooleanMethod(list_obj, list_add, tpoint_obj); //执行Arraylist类实例的add方法,添加一个stu对象
env->DeleteLocalRef(tpoint_obj);
}
env->SetObjectField(stu_obj, tpointFieldID, list_obj);
env->DeleteLocalRef(list_cls);
env->DeleteLocalRef(tpoint_cls);
env->DeleteLocalRef(list_obj);
env->DeleteLocalRef(stucls);
return stu_obj;
}
一定要注意应用类型的资源手动释放,如:jclass,jobject,jbyteArray,jstring等。
log:
D/jni_jokey: name: 小米
D/jni_jokey: id: 12345678
D/jni_jokey: age: 10
D/jni_jokey: height: 135.199997
D/jni_jokey: weight: 45.200001
D/jni_jokey: score: 80.500000
D/jni_jokey: sex: 女
D/jni_jokey: arraylist_size: 4
D/jni_jokey: i: 0
D/jni_jokey: x: 1.000000
D/jni_jokey: y: 1.000000
D/jni_jokey: i: 1
D/jni_jokey: x: 2.000000
D/jni_jokey: y: 2.000000
D/jni_jokey: i: 2
D/jni_jokey: x: 3.000000
D/jni_jokey: y: 3.000000
D/jni_jokey: i: 3
D/jni_jokey: x: 4.000000
D/jni_jokey: y: 4.000000
D/jokey: data: 896
D/jokey: stu: Student{name='小米', id=12345678, age=10, height=135.2, weight=45.2, score=80.5, sex=false, tpoints=[Tpoint{x=1.0, y=1.0}, Tpoint{x=2.0, y=2.0}, Tpoint{x=3.0, y=3.0}, Tpoint{x=4.0, y=4.0}]}
版权声明:本文为yuanjj5549原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。