Jni c调用Java

作者: 大旺旺的弟弟小旺旺 | 来源:发表于2021-10-21 23:01 被阅读0次

实现目标:

  • c对java调用的两种方式
  • 实现静态方法和成员方法
  • 跨线程完成调用
  • 写一个方法发回调

c对java调用的两种方式

方式一是通过传递过去一个实体,方式二是不传递实体,而是通过类名来创建的。
方式一:传递一个实体过去。
传递了实体,我们需要通过实体找到class类,通过class类来获取类的方法,然后通过实体来调用方法。

extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_JNIPeople(JNIEnv *env, jobject thiz, jobject people) {
//    需要获取方法,老方法 ,直接使用findclass 得到类class
    jclass peclass = env->GetObjectClass(people);
//    下面的一样   得到方法名字
    jmethodID setNam = env->GetMethodID(peclass,"setName", "(Ljava/lang/String;)V");
    jmethodID getNam = env->GetMethodID(peclass,"getName", "()Ljava/lang/String;");
    jmethodID setA = env->GetMethodID(peclass,"setAge", "(I)V");
    jmethodID getA = env->GetMethodID(peclass,"getAge", "()I");
//调用方法
    jstring xx = env->NewStringUTF("ddd");
    env->CallVoidMethod(people,setA,0);
    env->CallVoidMethod(people,setNam,xx);
    jint cc = env->CallIntMethod(people,getA);
    jobject names = env->CallObjectMethod(people,getNam);
//调用回调方法
    jmethodID inisuc = env->GetMethodID(peclass,"initSuccess", "()V");
    env->CallVoidMethod(people,inisuc);
}

方式二:类名创建
通过路径得到构造方法,通过构造方法创建实体。然后其他的和上面的一样。

/**
 * 使用类名的方式
 */
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_JNIPeopleFanshe(JNIEnv *env, jobject thiz) {
//    使用c++的方式创建字符串
    std::string clazzName = "com/example/ccalljava/People";
//  得到class
    jclass jscc = env->FindClass(clazzName.c_str());
//  得到构造方法
    jmethodID initMa = env->GetMethodID(jscc,"<init>","()V");
//  根据构造 方法创建对象
    jobject pInstance = env->NewObject(jscc,initMa);
////  我们得到里面的方法
    jmethodID psetName= env->GetMethodID(jscc,"setName","(Ljava/lang/String;)V");
    jmethodID psetAge= env->GetMethodID(jscc,"setAge","(I)V");
////    调用
    env->CallVoidMethod(pInstance,psetAge,1);
    jstring xx = env->NewStringUTF("ddd");
    env->CallVoidMethod(pInstance,psetName, xx);
}

这两种方式的思路也是很简单的,

java方法


public class People {
    private String name;
    private int age;

    public People(){
        System.out.println("------------  初始化");
    }

    public void setName(String name) {
        System.out.println("------------  setName"+name);
        this.name = name;
    }

    public void setAge(int age) {
        System.out.println("------------  setAge"+age);
        this.age = age;
    }

    public String getName() {
        System.out.println("------------  getName"+name);
        return name;
    }

    public int getAge() {
        System.out.println("------------  getAge"+age);
        return age;
    }

    public void initSuccess(){
        System.out.println("------------  success");
        listener.success();
    }

    private SuccessListener listener;
    public void setListener(SuccessListener listener){
        this.listener = listener;
    }

    interface SuccessListener{
        public void success();
    }
}

静态方法

    native void staticDemo();

    public static void testStatic(){
        System.out.println("----静态方法!");
    }
``

jni方法
```c++
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_staticDemo(JNIEnv *env, jobject thiz) {
    jclass thizClass = env->GetObjectClass(thiz);
    jmethodID xx = env->GetStaticMethodID(thizClass,"testStatic","()V");
    env->CallStaticVoidMethod(thizClass,xx);
}

线程创建对象

案例没跑起来,原因不知道,反正就是在子线程中一直无法找到类,需要注意的是跨线程需要使用到vm和env,我们可以在加载的时候初始化

JNIEnv *encz;
JavaVM *vm1;
extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){
    vm1 = vm;
    //获取JNI版本
    vm->GetEnv((void**)&encz, JNI_VERSION_1_6);
    return JNI_VERSION_1_6;
}

但是下面的就有点奇怪,就是跑不起来,一直找不到类


void* threadM(void *args){
//    JNIEnv *env;
//    vm1->GetEnv((void**)env, JNI_VERSION_1_6);
    int xx = vm1->AttachCurrentThread(&encz, NULL);
    //    使用c++的方式创建字符串
    std::string clazzName = "com/example/ccalljava/People";
//  得到class
    jclass jscc = encz->FindClass(clazzName.c_str());
//  得到构造方法
    jmethodID initMa = encz->GetMethodID(jscc,"<init>","()V");
//  根据构造 方法创建对象
//    jobject pInstance = env->NewObject(jscc,initMa);
//////  我们得到里面的方法
//    jmethodID psetName= env->GetMethodID(jscc,"setName","(Ljava/lang/String;)V");
//    jmethodID psetAge= env->GetMethodID(jscc,"setAge","(I)V");
//////    调用
//    env->CallVoidMethod(pInstance,psetAge,1);
//    jstring xx = env->NewStringUTF("ddd");
//    env->CallVoidMethod(pInstance,psetName, xx);
//    vm1->DetachCurrentThread();
    return 0;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_threadDemo(JNIEnv *env, jobject thiz) {
    pthread_t pid;
    pthread_create(&pid, 0, threadM, 0);
}

使用实体跨线程创建

这个需要注意是,需要对传如的对象进行全局化操作。

void* three(void* args){
//    读取数据包
    jobject people = static_cast<jobject>(args);
    JNIEnv *jniEnv;
    vm1->AttachCurrentThread(&jniEnv, NULL);
    jclass jscc = jniEnv->GetObjectClass(people);
    jmethodID xx = jniEnv->GetMethodID(jscc,"setAge","(I)V");
    jniEnv->CallVoidMethod(people,xx,1);
    return 0;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_ccalljava_MainActivity_threadDemoInstance(JNIEnv *env, jobject thiz,
                                                           jobject people) {
//    env->GetJavaVM(&vm1);
    pthread_t  pid;
//这句话很重要  因为在另一个线程里,这个方法结束了就会将数据清除了
    jobject p = env->NewGlobalRef(people);
    pthread_create(&pid,0,three,p);
}

使用类名加载不知道什么不行。

相关文章

网友评论

    本文标题:Jni c调用Java

    本文链接:https://www.haomeiwen.com/subject/ohffaltx.html