Android JNI 中 cpp 线程中调用 java 方法

Linux 下 JNI 实现 Java 调用 c的例子

 

c/cpp 调用 Java  方法的重点:

  • jclass 是由 jobject public 继承而来的子类,所以它当然是一个 jobject,需要创建一个 global reference 以便日后使用。
  • jmethodID/jfieldID 与 jobject 没有继承关系,它不是一个 jobject,只是个整数,所以不存在被释放与否的问题,可保存后直接使用。
  • JNIEnv 是一个与线程相关的变量,不同线程的 JNIEnv 彼此独立。
  • JavaVM是虚拟机在JNI层的代表,在一个虚拟机进程中只有一个JavaVM。
  • 反射 : 我们可以通过类或类对象得到 Class 类的对象,反过来,我们也可以由 Class 类的对象得到类的对象。

 

Android CPP 调用 Java 方法的步骤:

     0. 在注册 JNI 时,保存 JVM jobject 本地引用

  1. 获取线程中  java 运行环境: gJvm->AttachCurrentThread(&env, NULL)
  2. 获取  Java class 类 :jclass cls = env->FindClass("com/test/JNItest");
  3. 获取 java 的方法 ID : jmethodID jcallback=env->GetMethodID(jcls,"PreviewCallback","()V");
  4. 调用 java 方法(区分 静态和非静态方法):  env->CallVoidMethod(gJobj, jcallback); 
  5. 释放线程中  java 运行环境 : gJvm->DetachCurrentThread()

 

例如:

一. 在注册 JNI 时,保存 JVM jobject 本地引用

// 全局静态变量
static JavaVM *gJvm = NULL;
static jobject gJobj = NULL;

// 反射是相对极为消耗资源的,建议使用全局变量保存经常会使用的资源
//static jclass  gJcls = NULL;
//static jmethodID gJmethodID = NULL;

// 初始化
JNIEXPORT jint nativeInit(JNIEnv *env, jobject obj)
{
    if (obj == NULL)
    {
        return -1;
    }
    env->GetJavaVM(&gJvm);            // 获取虚拟机。并保存到 gJvm 中。也可在 JNI_OnLoad 中赋值
    gJobj = env->NewGlobalRef(obj);   // 创建对象的本地引用
    return 0;
}

// 去初始化
JNIEXPORT jint nativeUnInit(JNIEnv *env, jobject obj)
{
    cur_enter();
    if(gJobj != NULL)
    {
        env->DeleteGlobalRef(gJobj);
        gJobj = NULL;
    }
    return 0;
}

建议用 C 的格式声明 jni 函数

#ifndef JNI_TEST_H
#define JNI_TEST_H

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint nativeInit(JNIEnv *env, jobject obj);
JNIEXPORT jint nativeUnInit(JNIEnv *env, jobject obj);
JNIEXPORT jint nativeStart(JNIEnv *env, jobject obj);
JNIEXPORT jint nativeStop(JNIEnv *env, jobject obj);

#ifdef __cplusplus
}
#endif

#endif //JNI_NATIVE_CPP_JNI_TEST_H

 

二. JNI 中CPP 代码调用 JAVA 方法的步骤:

void Jnitest::ThreadLoop()
{
    cur_enter();
    int i = 0;
    JNIEnv *env = NULL;
    jclass jcls = NULL;
    jmethodID jcallback= NULL;
    while(mLoop)
    {
        i++;
        sleep(1);
        cur_logi("ThreadLoop state i = %d", i);
        // 1. 获取线程中  java 运行环境
        if(gJvm->AttachCurrentThread(&env, NULL) != JNI_OK)
        {
            cur_loge("%s: AttachCurrentThread() failed", __func__);
            return;
        }
        // 2. 获取  Java class 类
        jcls = env->GetObjectClass(gJobj); // 获取 class
        if(jcls != NULL)
        {
            cur_logi("find jcls success");
            // 3. 获取 java 的方法 ID methodID
            jcallback = env->GetMethodID(jcls,"PreviewCallback", "()V");
            // 4. 调用 java 方法
            if(jcallback != NULL)
            {
                env->CallVoidMethod(gJobj, jcallback);   // 调用Java方法
            }
        }
        // 5. 释放 java 运行环境
        if(gJvm->DetachCurrentThread() != JNI_OK)
        {
            cur_loge("%s: DetachCurrentThread() failed", __func__);
        }
    }
    cur_logi("ThreadLoop exit");
}

 

 三. Cap.java  注册 JNI native 方法

public class Cap
{
    static
    {
        System.loadLibrary("native");
    }
    private int mNativeContext;
    private final static String TAG = "myjnitest";

    public native int nativeInit();
    public native int nativeUnInit();
    public native int nativeStart();
    public native int nativeStop();

    // CPP 调用 JAVA
    public void PreviewCallback()
    {
        Log.d(TAG, "PreviewCallback OK");
    };
}

四. 运行结果:

下载链接: Android ndk cpp 线程运行 java 方法

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值