JNI 积累

参考:http://blog.csdn.net/qinjuning/article/details/7607214

1、动态加载函数

static JNINativeMethod gMethods[] = {
        {"chargerhdVersion", "()Ljava/lang/String;", (void *) jni_chargerhdVersion},
        {"setLedState",      "(III)V",               (void *) jni_setLedState},
        {"chargerhdInit","()V",(void*)jni_chargerhdInit},
        {"chargerhdUnInit","()V",(void*)jni_chargerhdUnInit},
};

int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods,
                          int numMethods) {
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

int registerNatives(JNIEnv *env) {
    const char *kClassName = CLASS_NAME;//指定要注册的类
    return registerNativeMethods(env, kClassName, gMethods,
                                 sizeof(gMethods) / sizeof(gMethods[0]));
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    g_vm = vm;
    JNIEnv *env = NULL;
    jint result = -1;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);
    if (!registerNatives(env)) {//注册
        return -1;
    }
    //成功
    result = JNI_VERSION_1_6;

    return result;
}
2、回调java接口

jint android::updateMeter(MeterInfo info) { //使用namespace括起来,供外部C调用
    bool isAttacked = false;
    jint javaIndex = -1;
    JNIEnv *env = NULL;
    int status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
    if (status < 0) {
        status = g_vm->AttachCurrentThread(&env, NULL);
        if (status < 0) {
            return -1;
        }
        isAttacked = true;
    }

    jclass clz = env->GetObjectClass(g_object);//获取加载.so的类 (g_object = env->NewGlobalRef(thiz);)
    //获取函数id
    jmethodID mid = env->GetMethodID(clz, "onMeterInfoChanged", "(Lcom/huliuda/rocky/MeterInfo;)V");
    if (mid) {
        jmethodID id = env->GetMethodID(g_jclass_meter,"<init>","()V");//获取构造函数
        jobject meter = env->NewObject(g_jclass_meter,id);//获取实例

        env->CallIntMethod(g_object, mid, meter);
        env->DeleteLocalRef(clz);
        env->DeleteLocalRef(meter);
    }

    if(isAttacked) {
        g_vm->DetachCurrentThread();
    }
    return javaIndex;
}

3、坑1:

在添加回调java层方法时,如果调用下面jni_chargerhdInit的java层方法,就能使用其中的"thiz"来创建jobject和jclass,否则会找不到准确的类和对象。

void jni_chargerhdInit(JNIEnv *env, jobject thiz){
    g_object = env->NewGlobalRef(thiz);
    g_jclass_meter = env->FindClass("com/atsmart/chargerhdservice/MeterInfo");
    g_jclass_meter = (jclass)env->NewGlobalRef(g_jclass_meter);
    monitor = new MeterMonitor();
}
4、坑2:

在回调自定义的java层对象时,需要先在主线程中预加载类,如上图

g_jclass_meter = env->FindClass("com/atsmart/chargerhdservice/MeterInfo");
然后调用如下:
jint android::updateMeter(MeterInfo info) {
    bool isAttacked = false;
    jint javaIndex = -1;
    JNIEnv *env = NULL;
    int status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
    if (status < 0) {
        status = g_vm->AttachCurrentThread(&env, NULL);
        if (status < 0) {
            return -1;
        }
        isAttacked = true;
    }

    jclass clz = env->GetObjectClass(g_object);
    //获取函数id
    jmethodID mid = env->GetMethodID(clz, "onMeterInfoChanged", "(Lcom/huliuda/rocky/MeterInfo;)V");
    if (mid) {
        jmethodID id = env->GetMethodID(g_jclass_meter,"<init>","()V");
        jobject meter = env->NewObject(g_jclass_meter,id);

        env->CallIntMethod(g_object, mid, meter);
        env->DeleteLocalRef(clz);
        env->DeleteLocalRef(meter);
    }

    if(isAttacked) {
        g_vm->DetachCurrentThread();
    }
    return javaIndex;
}

==============================================================
1、constant char* 转String
	// 定义java String类 strClass
        jclass strClass = env->FindClass("java/lang/String");//注意不是"Ljava/lang/String",否则报错
        // 获取java String类方法String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String
        jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
        // 建立byte数组
        jbyteArray bytes = env->NewByteArray((jsize)strlen(msg));
        // 将char* 转换为byte数组
        env->SetByteArrayRegion(bytes, 0, (jsize)strlen(msg), (jbyte*)msg);
        //设置String, 保存语言类型,用于byte数组转换至String时的参数
        jstring encoding = (env)->NewStringUTF("GB2312");
        //将byte数组转换为java String,并输出
        jstring msg = (jstring)(env)->NewObject(strClass, ctorID, bytes, encoding);


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值