Android jni 开发中 Integer 数值不正确的坑

这是一个让我记忆深刻的问题,排查这个问题差不多用了一个礼拜,每天都在不知所措中度过;其实当时这个问题并不会造成特别大的影响,只是在数值显示上有点问题,而且时间比较短;最开始是用 App 手动测试,测试人员都没有察觉到这个问题;后来自己上了自动化测试框架,才捕获了这个瞬间的问题。

问题现象:调用了通过 jni 封装的接口后,某一个固定的 Integer 数值一直输出不正确,类的实现如下图,很简单,就是赋值和输出
在这里插入图片描述
对应 Func 类的实现如下

public class Func {
    static {
        System.loadLibrary("jniFunc");
    }

    public static native int sum(int a, int b);

    public native int chg(Integer a);

    public native String getString();
}

对应的 native 方法实现如下

//
// Created by Administrator on 2019/11/22.
//

#include "com_hosh_myapplication_Func.h"

JNIEXPORT jint JNICALL Java_com_hosh_myapplication_Func_sum(JNIEnv * env, jclass jclaz, jint a, jint b)
{
    return a + b;
}

JNIEXPORT jint JNICALL Java_com_hosh_myapplication_Func_chg(JNIEnv * env, jobject jobj, jobject jintb)
{
    jclass objClass = env->GetObjectClass(jintb);
    if(objClass)
    {
        //获取相关数据;
        jfieldID intID = env->GetFieldID(objClass, "value", "I");
        jint nValue = (int)env->GetIntField(jintb, intID);

        //设置相关数据
        env->SetIntField(jintb, intID, 5);
    }
    return 0;
}

JNIEXPORT jstring JNICALL Java_com_hosh_myapplication_Func_getString(JNIEnv * env, jobject jobj)
{
    return env->NewStringUTF("I am from Jni in libjni-test.so !");
}

但是,对应的打印信息与预期有出入,日志如下
在这里插入图片描述
大家应该发现了 Integer inB = 1 后的打印信息是 com.hosh.myapplication E/XXX: inB=5,问题是,赋值结束后,直接打印,中间没有其他操作。这个是简化后的表现,当时处理的问题表现在 fastkson 解析后的数据一直不对,中间好长一段时间都在怀疑 fastjson 是不是有 bug,结果打脸了。哈哈,程序员就是在一直走歪路的路上,自我纠正

前面有提到,在调用某个 jni 接口以后出的上述问题,问题就是在 jni 的调用上。首先需要明白一个问题 Integer 的赋值操作, Integer a = 1Integer a = new Integer(1) 效果不一样,前者对应的是 Integer 的 valueOf 函数,我们需要看看源码的实现逻辑
在这里插入图片描述
在这里插入图片描述
大家应该发现了,当数值不在 [-127,128] 内时,返回一个 new 出来的新对象,当在此范围内时,返回数组中的一个值,即内存里的一个值。然而,我的 jni 代码里动了 Integer 的内存
在这里插入图片描述
这个时候,再通过赋值操作给 Integer 赋值的时候,其实是通过索引获取对应的数值,而索引对应的内存已经被修改

总结:处理完这个问题,自己也有很多感悟。一个是不要轻易的就用混合开发,看似是一套代码多个平台使用,但是各个平台上又会有很大的差异,需要针对不同的平台做调整;再一个,jni 排查问题,真的很麻烦,而且对于习惯原生开发的开发者来说很不友好,例如上面的这个问题,就涉及到了 Java 的 Integer 处理机制,还要了解 jni 的代码是怎么工作的;最后,就是如果真的用了 jni 尽量避免传递对象,因为,后续的兼容性可能会有问题

发布了23 篇原创文章 · 获赞 22 · 访问量 3891

猜你喜欢

转载自blog.csdn.net/qq_19154605/article/details/103205227