前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jni小细节操作

jni小细节操作

作者头像
曾大稳
发布2018-09-11 10:37:34
1.1K0
发布2018-09-11 10:37:34
举报
文章被收录于专栏:曾大稳的博客曾大稳的博客
  1. 数组的细节处理
代码语言:javascript
复制
#include <jni.h>
#include <string>
#include <stdlib.h>

int compare(const jint *a, const jint *b) {
    return *a - *b;
}


extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_sort(JNIEnv *env, jclass type, jintArray array_) {
    jint *intArray = env->GetIntArrayElements(array_, NULL);
    jsize length = env->GetArrayLength(array_);

    //排序
    //void *ptr	指向待排序的数组的指针
    //size_t count	数组的元素数目
    //size_t size  数组每个元素的字节大小
    // int (*comp)(const void *, const void *)  比较函数。若首个参数小于第二个,则返回负整数值,若首个参数大于第二个,
    // 则返回正整数值,若两参数相等,则返回零。
//    void qsort( void *ptr, size_t count, size_t size,int (*comp)(const void *, const void *) );

    qsort(intArray, static_cast<size_t>(length), sizeof(int),
          reinterpret_cast<int (*)(const void *, const void *)>(compare));

    //mode =
    //0 表示 既要同步数据给jArray,又要释放intArray
    //JNI_COMMIT : copy content, do not free buffer ,会同步数据给jArray,但是不会释放intArray
    //JNI_ABORT : free buffer w/o copying back ,不会同步数据给jArray,但是会释放intArray
    env->ReleaseIntArrayElements(array_, intArray, JNI_ABORT);
}

2.局部引用和全局引用

代码语言:javascript
复制
//局部变量
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_localRef(JNIEnv *env, jclass type) {

    //在Native层侯建的Java对象,不用了该怎么管理? 需要手动回收
    //在Java层开辟的内存由谁管理(JavaGC管理),能开辟多大内存?

    //字符串截取
    jclass str_clz = env->FindClass("java/lang/String");
    jmethodID init_str = env->GetMethodID(str_clz, "<init>", "()V");
    jobject j_str = env->NewObject(str_clz, init_str);
    //.....

    //jobject不使用了,需要回收。删除了就不能使用了
    env->DeleteLocalRef(j_str);
}



//全局变量,需要在合适的时机去释放 env->DeleteGlobalRef(globalStr);删除之后不能使用
jstring globalStr;
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_saveGlobalRef(JNIEnv *env, jclass type, jstring str_) {
    globalStr = static_cast<jstring>(env->NewGlobalRef(str_));
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_zzw_jnidemo_ArrayUtils_getStrGlobalRef(JNIEnv *env, jclass type) {

    return globalStr;
}

3.静态缓存策略

代码语言:javascript
复制
//局部静态缓存
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_staticLcalCache(JNIEnv *env, jclass type, jstring name_) {
//     jfieldID f_id =NULL;
    static jfieldID f_id = NULL;//局部缓存 ,这个方法会被多次调用,不需要反复去获取jfieldID
    if (!f_id) {
        f_id = env->GetStaticFieldID(type, "name", "Ljava/lang/String;");
    } else {
        LOGE("f_id不为null");//加上static将会缓存
    }
    env->SetStaticObjectField(type, f_id, name_);
}

//全局静态缓存

static jfieldID jfieldID1;
static jfieldID jfieldID2;
static jfieldID jfieldID3;
//一般初始化的时候调用
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_initStatic(JNIEnv *env, jclass type) {
    jfieldID1 = env->GetStaticFieldID(type, "name", "Ljava/lang/String;");
    jfieldID2 = env->GetStaticFieldID(type, "name1", "Ljava/lang/String;");
    jfieldID3 = env->GetStaticFieldID(type, "name2", "Ljava/lang/String;");
}

//如果反复调用设置值得函数,那么将不会每次都获取id
void setData(JNIEnv *env, jclass jclazz, jobject object) {
    env->SetStaticObjectField(jclazz, jfieldID1, object);
    env->SetStaticObjectField(jclazz, jfieldID2, object);
    env->SetStaticObjectField(jclazz, jfieldID3, object);
}

4.异常处理

代码语言:javascript
复制

extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_exception2(JNIEnv *env, jclass cls) {
    jthrowable exc = NULL;
    jmethodID mid = env->GetStaticMethodID(cls, "exceptionCallback", "()V");
    if (mid != NULL) {
        env->CallStaticVoidMethod(cls, mid);
    }
    LOGE("In C: Java_com_zzw_jnidemo_ArrayUtils_exception2-->called!!!!");
    //这种也是可以检测的
//    exc = env->ExceptionOccurred();  // 返回一个指向当前异常对象的引用
//    if (exc) {

    if (env->ExceptionCheck()) {  // 检查JNI调用是否有引发异常
        env->ExceptionDescribe();//打印错误信息
        env->ExceptionClear();        // 清除引发的异常,在Java层不会打印异常的堆栈信息
        env->ThrowNew(env->FindClass("java/lang/Exception"), "JNI抛出的异常!");
        return;
    }
    //补救  。。。
    mid = env->GetStaticMethodID(cls, "normalCallback", "()V");
    if (mid != NULL) {
        env->CallStaticVoidMethod(cls, mid);
    }
}



     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        try {
            ArrayUtils.exception();
        } catch (Exception e) {
            e.printStackTrace();//打印抛出的异常
        }
    }
  1. c++调用java: 这里需要分为在主线程调用还是在子线程调用,在主线程调用就直接通过函数的env调用即可,在子线程调用则需要JavaVM ->AttachCurrentThread拿到env然后调用。
代码语言:javascript
复制


#include "JavaListener.h"
JavaVM *jvm;

JavaListener *javaListener;

pthread_t chidlThread;


void *childCallback(void *data)
{
    JavaListener *javaListener1 = (JavaListener *) data;
    //子线程调用
    javaListener1->onError(0, 101, "c++ call java meid from child thread!");
    pthread_exit(&chidlThread);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnithread_ThreadDemo_callbackFromC(JNIEnv *env, jobject instance) {

    javaListener = new JavaListener(jvm, env, env->NewGlobalRef(instance));
    //主线程调用
    //javaListener->onError(1, 100, "c++ call java meid from main thread!");
    //子线程调用
    pthread_create(&chidlThread, NULL, childCallback, javaListener);

}



JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void* reserved)
{
    JNIEnv *env;
    jvm = vm;
    if(vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK)
    {
        return -1;
    }
    return JNI_VERSION_1_6;
}

JavaListener.h

代码语言:javascript
复制

#include "jni.h"

#ifndef JNITHREAD_JAVALISTENER_H
#define JNITHREAD_JAVALISTENER_H


class JavaListener {

public:
    JavaVM *jvm;
    _JNIEnv *jenv;
    jobject jobj;
    jmethodID jmid;
public:
    JavaListener(JavaVM *vm, _JNIEnv *env, jobject obj);
    ~JavaListener();

    /**
     * 1:主线程
     * 0:子线程
     * @param type
     * @param code
     * @param msg
     */
    void onError(int type, int code, const char *msg);


};


#endif //JNITHREAD_JAVALISTENER_H

JavaListener.cpp

代码语言:javascript
复制

#include "JavaListener.h"


void JavaListener::onError(int type, int code, const char *msg) {

    if(type == 0)
    {
        JNIEnv *env;
        jvm->AttachCurrentThread(&env, 0);
        jstring jmsg = env->NewStringUTF(msg);
        env->CallVoidMethod(jobj, jmid, code, jmsg);
        env->DeleteLocalRef(jmsg);

        jvm->DetachCurrentThread();


    }
    else if(type == 1)
    {
        jstring jmsg = jenv->NewStringUTF(msg);
        jenv->CallVoidMethod(jobj, jmid, code, jmsg);
        jenv->DeleteLocalRef(jmsg);
    }
}

JavaListener::JavaListener(JavaVM *vm, _JNIEnv *env, jobject obj) {

    jvm = vm;
    jenv = env;
    jobj = obj;

    jclass clz = env->GetObjectClass(jobj);
    if(!clz)
    {
        return;
    }
    jmid = env->GetMethodID(clz, "onError", "(ILjava/lang/String;)V");
    if(!jmid)
        return;


}

ThreadDemo.java

代码语言:javascript
复制
public class ThreadDemo {

    static
    {
        System.loadLibrary("native-lib");
    }

    private OnErrerListener onErrerListener;

    public void setOnErrerListener(OnErrerListener onErrerListener) {
        this.onErrerListener = onErrerListener;
    }

    public void onError(int code, String msg)
    {
        if(onErrerListener != null)
        {
            onErrerListener.onError(code, msg);
        }
    }

    public interface OnErrerListener
    {
        void onError(int code, String msg);
    }

    public native  void callbackFromC();

}

-------------The End-------------

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档