Adnroid jni数据传递大全,看这篇就够了

2024-05-29 23:48

本文主要是介绍Adnroid jni数据传递大全,看这篇就够了,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

        这次总结一下jni数据交互(通讯)的方式,本篇侧重应用,native层主要用C++编写。掌握数据交互方式,对入门jni及理解java与C++的数据类型映射起到四两拨千斤的作用。本编着重jni数据传递实现,跳过jni开发环境搭建及jni基础知识(网上基本可以找到对应解决方案)。

        平时为了实现某个功能(RFID编解码库),如果C++开发那边已经有现成的C++类库,再用java进行重复的工作就没必要了。我们只需提供接口java层调用即可,如果C++大佬没空,接口层代码自己也可以实现,最后在编译成Android平台调用的so库。so库可以自己使用,也可以给客户使用,不用担心代码被反编译的问题。

本次实现jni数据交互方式(jni静态注册)如图所示: 

 

jni编译的方式

  1. 使用Cmake文件编译
  2. 使用mk文件编译(这次使用mk文件编译)

环境(知识jni开发的环境)准备:

这两种方式都可以编译调试 ,如果只是调试native与java层代码,是不需要执行ndk-build命令(生成不同cpu架构的so库)。

jni开发流程

  1. 编写java本地方法
  2. 生成.h头文件 , 使用java命令是javah(必须在包名外使用javah命令)

  1. 创建jni目录,引入头文件,根据头文件实现C/C++代码
  2. 编写Android.mk、Application.mk文件
  3. Ndk编译生成动态库
  4. Java代码load动态库,调用native代码

知识准备

java方法签名查看

查看系统java系统方法 

javap -s java.lang.String 

查看自定义类(在class目录下执行):

javap -s  com.sjl.jnidata.JniDataTransfer

C和C++函数时的JNI使用区别 

jni.h头文件中对于*.c & *.cpp采用不同的定义,在C的定义中,env是二级指针,C需要对env指针进行双重deferencing,而且须将env作为第一个参数传给jni函数;而在C++的定义中,env是一级指针。

  • 在 C 中,JNI 函数调用由“(*env)->”作前缀,目的是为了取出函数指针所引用的值;
  • 在 C++ 中,JNIEnv 类拥有处理函数指针查找的内联成员函数。

举栗子:
C 语法(.c文件):jsize len = (*env)->GetArrayLength(env,array);
C++ 语法( .cpp文件):jsize len =env->GetArrayLength(array);

常见错误 

1. javah生成头文件报错:编码GBK的不可映射字符

解决方法:javah -jni -encoding UTF-8  类名

2.运行项目报错:

解决方法:

 退出应用或者点击终止项目或者清理项目

 jni数据传递

        native层处理java层数据,简单说就是C++仿java的写法,java几行代码实现,在native实现可能需要多行实现。举个例子简单说明一下,分别用java构造器java反射,C++三种方式创建同一个对象作为对比。

假设有这么一个类Simple:

package com.sjl.jnidata;public class Simple {private String a;private int b;public Simple() {}public Simple(String a, int b) {this.a = a;this.b = b;}//省略get,set方法...
}

 使用java构造器:

 Simple simple = new Simple("李四",99);

 使用java反射:

  try {Class<?> clz = Class.forName("com.sjl.jnidata.Simple");Constructor<?> constructor = clz.getConstructor(String.class, int.class);Object obj = constructor.newInstance("李四", 99);Simple simple = (Simple) obj;} catch (Exception e) {e.printStackTrace();}

 使用C++:

jclass simpleClz = env->FindClass("com/sjl/jnidata/Simple");
jmethodID constructorMID = env->GetMethodID(simpleClz, "<init>", "(Ljava/lang/String;I)V");//获取Simple的构造器
jstring str = env->NewStringUTF("李四");
jobject object = env->NewObject(simpleClz, constructorMID, str, 99);//object就是Simple对象 

从上面发现C++创建对象与java的反射创建对象类似 。

回到正题,介绍jni数据传递,下面所有native方法所在类名为:JniDataTransfer

 1.java传递基本类型数据到C++(带参数且有返回值)

java native:

/*** 测试基本类型** @param b* @param i* @param c* @param d* @param str* @return*/public static native String testPrimitiveType(byte b, int i, char c, double d, String str);

C++实现:

/** 带参数且有返回值*/
JNIEXPORT jstring JNICALL Java_com_sjl_jnidata_JniDataTransfer_testPrimitiveType(JNIEnv *env, jclass clz, jbyte b, jint i, jchar c, jdouble d, jstring str) {int index = (int) (b + i + c + d);LOGI("index=%d", index);const char *strContent = env->GetStringUTFChars(str, JNI_FALSE);env->ReleaseStringUTFChars(str, strContent);return env->NewStringUTF(strContent);
}

测试示例:

        String hello = JniDataTransfer.testPrimitiveType((byte) 0x1, 2, '3', 4.5, "hello world");

此处返回hello world. 

 2.java传递基本类型数据到C++(无参数且有返回值) 

java native:

/*** 获取当前时间戳** @return*/public static native long getCurrentTime();

 C++实现:


/*** 获取当前时间* @return*/
long long getCurrentTime() {struct timeval tv;gettimeofday(&tv, NULL);long long ts = (long long) tv.tv_sec * 1000 + tv.tv_usec / 1000;//64位,不加在64位系统会溢出,导致时间不准return ts;
}/** 无参数且有返回值*/
JNIEXPORT jlong JNICALL Java_com_sjl_jnidata_JniDataTransfer_getCurrentTime(JNIEnv *env, jclass clz) {long long time = getCurrentTime();return time;
}

 测试示例:

long currentTime = JniDataTransfer.getCurrentTime();

 输出结果:

3.java传递基本类型数据到C++(用byte[]接收数据,并返回数据长度) 

java native:

   /*** 这个实际用的比较多** @param sendData* @param resultData* @return*/public static native int testBytes(byte[] sendData, byte[] resultData);

  C++实现:

/**用byte[]接收数据*/
JNIEXPORT jint JNICALL Java_com_sjl_jnidata_JniDataTransfer_testBytes(JNIEnv *env, jclass clz, jbyteArray sendData, jbyteArray resultData) {jbyte *send = env->GetByteArrayElements(sendData, NULL);int nLength = env->GetArrayLength(sendData);//字节数组长度jbyte *result = env->GetByteArrayElements(resultData, NULL);int nLength2 = env->GetArrayLength(resultData);//字节数组长度if (nLength > nLength2) {env->ReleaseByteArrayElements(sendData, send, 0);//释放env->ReleaseByteArrayElements(resultData, result, 0);//释放return -1;}for (int i = 0; i < nLength; i++) {result[i] = send[i];}env->ReleaseByteArrayElements(sendData, send, 0);//释放env->ReleaseByteArrayElements(resultData, result, 0);//释放return nLength;
}

测试示例:

 byte[] sendData = new String("hello world").getBytes();byte[] resultData = new byte[32];int length = JniDataTransfer.testBytes(sendData, resultData);

resultData转成字符串就是hello world

 4.java传据递引用数类型到C++(传递简单对象数据)

java native: 

  /*** 测试传递简单对象** @param simple* @return*/public static native void testObj(Simple simple);

Simple类:

package com.sjl.jnidata;/*** TODO** @author Kelly* @version 1.0.0* @filename Simple.java* @time 2019/7/31 11:32* @copyright(C) 2019 song*/
public class Simple {public Simple() {}/*** native层使用* @param a* @param b*/public Simple(String a, int b) {this.a = a;this.b = b;}private String a;private int b;public String getA() {return a;}public void setA(String a) {this.a = a;}public int getB() {return b;}public void setB(int b) {this.b = b;}@Overridepublic String toString() {return "Simple{" +"a='" + a + '\'' +", b=" + b +'}';}
}

 C++实现:

/** 传递简单对象*/
JNIEXPORT void JNICALL Java_com_sjl_jnidata_JniDataTransfer_testObj(JNIEnv *env, jclass clz, jobject obj) {jclass simple_cls = env->GetObjectClass(obj);if (simple_cls == NULL) {LOGW("GetObjectClass failed");return;}//获得属性字段jfieldID field_a = env->GetFieldID(simple_cls, "a", "Ljava/lang/String;");jfieldID field_b = env->GetFieldID(simple_cls, "b", "I");//获得属性值jstring a = (jstring) env->GetObjectField(obj, field_a);jint b = env->GetIntField(obj, field_b);const char *c_name = env->GetStringUTFChars(a, NULL);//释放引用env->ReleaseStringUTFChars(a, c_name);LOGI("print simple obj:a=%s,b=%d", c_name, b);
}

 测试示例:

 Simple simple = new Simple();simple.setA("李四");simple.setB(99);JniDataTransfer.testObj(simple);

输出结果:

 

5.java传据递引用数类型到C++(传递复杂对象数据)

java native: 

 /*** 测试传递复杂对象** @param person* @return*/public static native void testComplexObj(Person person);

Person类:

package com.sjl.jnidata;import java.util.List;
import java.util.Map;/*** TODO** @author Kelly* @version 1.0.0* @filename Person.java* @time 2019/7/31 11:11* @copyright(C) 2019 song*/
public class Person {private String name;//姓名private int age;//年龄private List<String> label;//个性标签private List<Woman> womanList;//女人private Map<String,Woman> womanMap;//女人映射public Person() {}/**** native层使用* @param name* @param age* @param label* @param womanList* @param womanMap*/public Person(String name, int age, List<String> label, List<Woman> womanList, Map<String, Woman> womanMap) {this.name = name;this.age = age;this.label = label;this.womanList = womanList;this.womanMap = womanMap;}public static class Woman {private String name;public Woman() {}public Woman(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Woman{" +"name='" + name + '\'' +'}';}}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 List<String> getLabel() {return label;}public void setLabel(List<String> label) {this.label = label;}public List<Woman> getWomanList() {return womanList;}public void setWomanList(List<Woman> womanList) {this.womanList = womanList;}public Map<String, Woman> getWomanMap() {return womanMap;}public void setWomanMap(Map<String, Woman> womanMap) {this.womanMap = womanMap;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", label=" + label +", womanList=" + womanList +", womanMap=" + womanMap +'}';}
}

C++实现:

/**** 传递复杂对象*/
void JNICALL Java_com_sjl_jnidata_JniDataTransfer_testComplexObj(JNIEnv *env, jclass clz, jobject obj) {jclass complex_cls = env->GetObjectClass(obj);if (complex_cls == NULL) {LOGW("GetObjectClass failed");return;}//获得属性字段jfieldID field_name = env->GetFieldID(complex_cls, "name", "Ljava/lang/String;");jfieldID field_age = env->GetFieldID(complex_cls, "age", "I");jfieldID field_label = env->GetFieldID(complex_cls, "label", "Ljava/util/List;");jfieldID field_woman = env->GetFieldID(complex_cls, "womanList", "Ljava/util/List;");jfieldID field_womanMap = env->GetFieldID(complex_cls, "womanMap", "Ljava/util/Map;");//特别注意:如果java传过来对象字段没有赋值,Get***Field是空的//捕获异常try {//获得属性值jstring name = (jstring) env->GetObjectField(obj, field_name);jint age = env->GetIntField(obj, field_age);const char *c_name = env->GetStringUTFChars(name, NULL);//释放引用env->ReleaseStringUTFChars(name, c_name);LOGI("=========print complex obj start:");LOGI("name=%s,age=%d", c_name, age);//处理label List<String>jobject labelObj = (jobject) env->GetObjectField(obj, field_label);checkNull(labelObj, "labelObj is null.");//获取List classjclass labelCls = env->GetObjectClass(labelObj);//获取List的MethodIDjmethodID label_get = env->GetMethodID(labelCls, "get", "(I)Ljava/lang/Object;");jmethodID label_size = env->GetMethodID(labelCls, "size", "()I");int labelSize = env->CallIntMethod(labelObj, label_size);for (int i = 0; i < labelSize; i++) {jobject label_obj = env->CallObjectMethod(labelObj, label_get, i);jstring str = (jstring) label_obj;const char *name = env->GetStringUTFChars(str, NULL);//拿到标签名字if (name == NULL) {continue;}env->ReleaseStringUTFChars(str, name);LOGI("print label list 第%d个标签:name=%s", i + 1, name);}//处理woman List<Woman>jobject womanObj = env->GetObjectField(obj, field_woman);checkNull(womanObj, "womanObj is null.");//获取List classjclass womanCls = env->GetObjectClass(womanObj);//获取List的MethodIDjmethodID woman_get_id = env->GetMethodID(womanCls, "get", "(I)Ljava/lang/Object;");jmethodID woman_size_id = env->GetMethodID(womanCls, "size", "()I");int womanSize = env->CallIntMethod(womanObj, woman_size_id);for (int i = 0; i < womanSize; i++) {//通过get方法获取jobject woman_obj = env->CallObjectMethod(womanObj, woman_get_id, i);jclass woman_cls = env->GetObjectClass(woman_obj);jmethodID nameId = env->GetMethodID(woman_cls, "getName", "()Ljava/lang/String;");jstring nameStr = (jstring) env->CallObjectMethod(woman_obj, nameId);const char *name = env->GetStringUTFChars(nameStr, NULL);//拿到名字if (name == NULL) {continue;}env->ReleaseStringUTFChars(nameStr, name);env->DeleteLocalRef(woman_obj);env->DeleteLocalRef(nameStr);LOGI("print woman list 第%d个女人:name=%s", i + 1, name);}jobject womanMapObj = env->GetObjectField(obj, field_womanMap);checkNull(womanMapObj, "womanMapObj is null.");//这样也可以获取jclass womanMapCls = env->FindClass("java/util/Map");jmethodID methodID_womanMap = env->GetMethodID(womanMapCls, "size", "()I");int womanMapSize = env->CallIntMethod(womanMapObj, methodID_womanMap);//map//使用iterator遍历if (womanMapSize > 0) {jmethodID entrySetMID = env->GetMethodID(womanMapCls, "entrySet", "()Ljava/util/Set;");jobject setObj = env->CallObjectMethod(womanMapObj, entrySetMID);jclass setClass = env->FindClass("java/util/Set");jmethodID iteratorMID = env->GetMethodID(setClass, "iterator","()Ljava/util/Iterator;");jobject iteratorObj = env->CallObjectMethod(setObj, iteratorMID);jclass iteratorClz = env->FindClass("java/util/Iterator");jmethodID hasNextMID = env->GetMethodID(iteratorClz, "hasNext", "()Z");jmethodID nextMID = env->GetMethodID(iteratorClz, "next", "()Ljava/lang/Object;");//内部类使用$符号表示jclass entryClass = env->FindClass("java/util/Map$Entry");jmethodID getKeyMID = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");jmethodID getValueMID = env->GetMethodID(entryClass, "getValue","()Ljava/lang/Object;");while (env->CallBooleanMethod(iteratorObj, hasNextMID)) {jobject entryObj = env->CallObjectMethod(iteratorObj,nextMID);//这个对应 Map.Entry<String, Person.Woman>jstring key = (jstring) env->CallObjectMethod(entryObj, getKeyMID);if (key == NULL) {continue;}const char *keyStr = env->GetStringUTFChars(key, NULL);jobject woman_obj = env->CallObjectMethod(entryObj, getValueMID);if (woman_obj == NULL) {continue;}jclass label_cls = env->GetObjectClass(woman_obj);jmethodID nameId = env->GetMethodID(label_cls, "getName", "()Ljava/lang/String;");jstring name = (jstring) env->CallObjectMethod(woman_obj, nameId);const char *nameStr = env->GetStringUTFChars(name, NULL);//拿到名字// 释放UTF字符串资源env->ReleaseStringUTFChars(key, keyStr);env->ReleaseStringUTFChars(name, nameStr);// 释放JNI局部引用资源env->DeleteLocalRef(entryObj);env->DeleteLocalRef(woman_obj);env->DeleteLocalRef(key);LOGI("print woman map 我与女人的映射关系:key=%s,name=%s", keyStr, nameStr);}}env->DeleteLocalRef(labelObj);env->DeleteLocalRef(womanObj);env->DeleteLocalRef(womanMapObj);LOGI("=========print complex obj end");} catch (NullException err) {LOGE("print complex obj error:%s", err.what());} catch (exception err) {//其它异常LOGE("print complex obj error:%s", err.what());}
}

细心的你可能会发现这与java的反射类似。 

  测试示例:

 Person person = new Person();person.setName("李四");person.setAge(99);List<String> label = Arrays.asList("唱", "跳", "rap", "篮球");List<Person.Woman> womanList = new ArrayList<>();Person.Woman woman1 = new Person.Woman();woman1.setName("恭喜");Person.Woman woman2 = new Person.Woman();woman2.setName("发财");womanList.add(woman1);womanList.add(woman2);Map<String, Person.Woman> womanMap = new HashMap<>();for (Person.Woman woman : womanList) {womanMap.put(person.getName() + ":" + woman.getName(), woman);}person.setLabel(label);person.setWomanList(womanList);person.setWomanMap(womanMap);JniDataTransfer.testComplexObj(person);

输出结果: 

 

 6.java调用C++,native层操作java数据(返回简单对象数据)

java native: 

 /*** 测试返回简单对象** @return*/public static native Simple testGetObj();

C++实现:

/**返回简单对象*/
JNIEXPORT jobject JNICALL Java_com_sjl_jnidata_JniDataTransfer_testGetObj(JNIEnv *env, jclass clz) {jclass simpleClz = env->FindClass("com/sjl/jnidata/Simple");//获得构造函数,函数名为 <init> 返回类型必须为 void 即 VjmethodID constructorMID = env->GetMethodID(simpleClz, "<init>", "(Ljava/lang/String;I)V");char buff[100] = {0};char *pos = buff;int strLen = sprintf(pos, "%s:", "hello world from c++");pos += strLen;sprintf(pos, "%lli", getCurrentTime());jstring str = env->NewStringUTF(buff);jobject object = env->NewObject(simpleClz, constructorMID, str, 123456);env->DeleteLocalRef(str);return object;
}

 测试示例:

        Simple simple = JniDataTransfer.testGetObj();

输出结果:  

 7.java调用C++,native层操作java数据(返回复杂对象数据)

java native: 

 /*** 测试返回复杂对象** @return*/public static native Person testGetComplexObj();

 C++实现:

/** 返回复杂对象*/
JNIEXPORT jobject JNICALL Java_com_sjl_jnidata_JniDataTransfer_testGetComplexObj(JNIEnv *env, jclass clz) {jclass personClz = env->FindClass("com/sjl/jnidata/Person");//获得构造函数,函数名为 <init> 返回类型必须为 void 即 V//如果不通过构造器赋值,可以选择set赋值jmethodID constructorMID = env->GetMethodID(personClz, "<init>","(Ljava/lang/String;ILjava/util/List;Ljava/util/List;Ljava/util/Map;)V");jstring p_name = env->NewStringUTF("李四");jint p_age = 26;jclass list_cls = env->FindClass("java/util/ArrayList");jmethodID listConstructorMID = env->GetMethodID(list_cls, "<init>", "()V");//处理List<Label>jobject label_list_obj = env->NewObject(list_cls, listConstructorMID);jmethodID label_list_add = env->GetMethodID(list_cls, "add", "(Ljava/lang/Object;)Z");env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("唱"));env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("跳"));env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("rap"));env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("篮球"));//处理List<Woman>jobject woman_list_obj = env->NewObject(list_cls, listConstructorMID);jmethodID woman_list_add = env->GetMethodID(list_cls, "add", "(Ljava/lang/Object;)Z");jclass woman_cls = env->FindClass("com/sjl/jnidata/Person$Woman");//获得Woman类jmethodID woman_constructor = env->GetMethodID(woman_cls, "<init>", "(Ljava/lang/String;)V");jstring woman1 = env->NewStringUTF("恭喜");jobject woman_obj1 = env->NewObject(woman_cls, woman_constructor, woman1);env->CallBooleanMethod(woman_list_obj, woman_list_add, woman_obj1);jstring woman2 = env->NewStringUTF("发财");jobject woman_obj2 = env->NewObject(woman_cls, woman_constructor, woman2);env->CallBooleanMethod(woman_list_obj, woman_list_add, woman_obj2);//处理Map<String,Woman>jclass map_cls = env->FindClass("java/util/HashMap");jmethodID mapConstructorMID = env->GetMethodID(map_cls, "<init>", "()V");jobject woman_map_obj = env->NewObject(map_cls, mapConstructorMID);jmethodID woman_map_put = env->GetMethodID(map_cls, "put","(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");env->CallObjectMethod(woman_map_obj, woman_map_put, env->NewStringUTF("李四:恭喜"), woman_obj1);env->CallObjectMethod(woman_map_obj, woman_map_put, env->NewStringUTF("李四:发财"), woman_obj2);jobject object = env->NewObject(personClz, constructorMID, p_name, p_age, label_list_obj,woman_list_obj, woman_map_obj);env->DeleteLocalRef(woman1);env->DeleteLocalRef(woman2);env->DeleteLocalRef(label_list_obj);env->DeleteLocalRef(woman_list_obj);env->DeleteLocalRef(woman_map_obj);return object;
}

测试示例:

        Person testGetComplexObj = JniDataTransfer.testGetComplexObj();

输出结果:  

从上面可以看出C++层解析java对象比构建java对象稍微复杂一些,总之,实现思路和java思想一致。 

 8.java调用C++,native层操作java数据(C++对java对象变量设置值)

java native: 

  private String name = "java";/*** C++赋值java变量*/public native void setFieldValue();public String getName() {return name;}

 C++实现:


/** C++修改java字段值*/
JNIEXPORT void JNICALL Java_com_sjl_jnidata_JniDataTransfer_setFieldValue(JNIEnv *env, jobject obj) {//如果是静态方法,第二个参数是classjclass cls = env->GetObjectClass(obj);jfieldID nameFieldId = env->GetFieldID(cls, "name", "Ljava/lang/String;");char new_name[] = "C++设置java字段值成功";jstring cName = env->NewStringUTF(new_name);env->SetObjectField(obj, nameFieldId, cName);//修改对象实例值
}

 测试示例:

 JniDataTransfer jniDataTransfer = new JniDataTransfer();String name1 = jniDataTransfer.getName();jniDataTransfer.setFieldValue();String name2 = jniDataTransfer.getName();

输出结果:  

 9.java调用C++,native层操作java数据(C++回调java接口方法)

java native: 

  private JniDataListener jniDataListener;/*** 回调成功还是异常控制标志** @param flag*/public native void setFlag(boolean flag);/*** C++回调java成功*/public void callSuccess(String msg) {if (jniDataListener != null) {jniDataListener.onSuccess(msg);}}/*** C++回调java异常*/public void callError(Exception e) {if (jniDataListener != null) {jniDataListener.onError(e);}}public interface JniDataListener {void onSuccess(String msg);void onError(Exception e);}public void setJniDataListener(JniDataListener jniDataListener) {this.jniDataListener = jniDataListener;}

 C++实现:

/** C++回调java*/
JNIEXPORT void JNICALL Java_com_sjl_jnidata_JniDataTransfer_setFlag(JNIEnv *env, jobject obj, jboolean b) {jclass cls = env->GetObjectClass(obj);jmethodID callSuccessFieldId = env->GetMethodID(cls, "callSuccess", "(Ljava/lang/String;)V");jmethodID callErrorFieldId = env->GetMethodID(cls, "callError", "(Ljava/lang/Exception;)V");if (b) {jstring msg = env->NewStringUTF("来自C++回调,成功");//回调成功方法,并传递参数env->CallVoidMethod(obj , callSuccessFieldId , msg);} else {jstring msg = env->NewStringUTF("来自C++回调,异常");jclass exceptionClz = env->FindClass("java/lang/Exception");jmethodID constructorMID = env->GetMethodID(exceptionClz, "<init>", "(Ljava/lang/String;)V");jobject object = env->NewObject(exceptionClz, constructorMID, msg);env->CallVoidMethod(obj, callErrorFieldId , object);}
}

 测试示例:

 boolean callbackFlag = true;public void callbackJava(View view) {JniDataTransfer jniDataTransfer = new JniDataTransfer();//设置监听jniDataTransfer.setJniDataListener(new JniDataTransfer.JniDataListener() {@Overridepublic void onSuccess(String msg) {showMsg("回调成功:" + msg + "");callbackFlag = false;}@Overridepublic void onError(Exception e) {showMsg("回调异常:" + e.getMessage());callbackFlag = true;}});jniDataTransfer.setFlag(callbackFlag);}

demo地址 

 https://github.com/kellysong/jni-data-transfer 

总结

         本文章举例了多种jni数据传递方式,实际开发中涉及业务逻辑,更复杂,开发中需要注意java类包名和方法签名是否正确,避免出现比必要的麻烦,希望这篇文章能够帮助有jni开发需求的人。

这篇关于Adnroid jni数据传递大全,看这篇就够了的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1014978

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

pandas数据过滤

Pandas 数据过滤方法 Pandas 提供了多种方法来过滤数据,可以根据不同的条件进行筛选。以下是一些常见的 Pandas 数据过滤方法,结合实例进行讲解,希望能帮你快速理解。 1. 基于条件筛选行 可以使用布尔索引来根据条件过滤行。 import pandas as pd# 创建示例数据data = {'Name': ['Alice', 'Bob', 'Charlie', 'Dav