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;
    }

    @Override
    public 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;
        }

        @Override
        public 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;
    }

    @Override
    public 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 class
        jclass labelCls = env->GetObjectClass(labelObj);

        //获取List的MethodID
        jmethodID 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 class
        jclass womanCls = env->GetObjectClass(womanObj);

        //获取List的MethodID
        jmethodID 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 即 V
    jmethodID 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) {//如果是静态方法,第二个参数是class
    jclass 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() {
            @Override
            public void onSuccess(String msg) {
                showMsg("回调成功:" + msg + "");
                callbackFlag = false;
            }

            @Override
            public void onError(Exception e) {
                showMsg("回调异常:" + e.getMessage());
                callbackFlag = true;
            }
        });

        jniDataTransfer.setFlag(callbackFlag);

    }

demo地址 

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

总结

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

猜你喜欢

转载自blog.csdn.net/u011082160/article/details/97912349
今日推荐