Android 在JNI主线程调用Java方法

1. C++ 全局调用Java方法

1.1 C++主线程调用Java方法

在 Android C++多线程-创建子线程中演示了在 Java 层调用 native 层的方法,但是如何在 native 层去调用 Java 层的方法呢?
下面这个类,我们想在调用 callJavaMethodOnCPPMainThread 方法之后,然后在 native 层回调 JniThreadDemoonSuccess 的方法。

public class JniThreadDemo {

    private static final String TAG = JniThreadDemo.class.getSimpleName();

    static {
        System.loadLibrary("native-thread-lib");
    }
    //在主线程中调用 onSuccess 方法
    public native void callJavaMethodOnCPPMainThread();

    public void onSuccess(String msg) {
        Log.i(TAG, "JNI 回调 Java层 onSuccess 方法:" + msg);
    }
}

实际的调用函数

public void callJavaMethodOnCppMainThread(View view) {
    JniThreadDemo jniThreadDemo = new JniThreadDemo();
    //在主线程调用
    jniThreadDemo.callJavaMethodOnCPPMainThread();
}

上面演示的只是调用了 jniThreadDemo.callJavaMethodOnCPPMainThread 函数,下面我们来看看如何在 native 层去回调 onSuccess 函数的。

1.2 native 回调 Java 层函数的过程

这个过程类似于 Java 的反射过程,例如下面的例子

public class JniThreadDemo {

  public void onSuccess(String msg) {
     System.out.println("onSuccess invoke.."+ msg);
  }

  public static void main(String[] args) {
      try {
          Class clz = JniThreadDemo.class;
          Method method = clz.getMethod("onSuccess", String.class);
          JniThreadDemo jniThreadDemo = clz.newInstance();
          method.invoke(jniThreadDemo, "反射");
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
}

下面来看一下,Jni 时如何调用 Java 层的函数的。

1.2.1 获取到 jclass

根据 jobject 获取到 jclass

jclass jclz = env->GetObjectClass(instance);

1.2.2 获取到 jmethodid

因为要回调 Java 层的 onSuccess 函数,所以需要在这里定义具体要调用的函数名字和函数签名,具体如何获取函数签名,请点击JNI函数签名来了解

jmethodID jmethod = env->GetMethodID(jclz, "onSuccess", "(Ljava/lang/String;)V");

1.2.3 调用 Java 方法

jenv->CallVoidMethod(jobj, jmid, code, jmsg) 

下面是 C++ 的全部代码

//在 c++ 主线程调用 Java 方法。
extern "C"
JNIEXPORT void JNICALL
Java_com_liaowj_jni_thread_JniThreadDemo_callJavaMethodOnCPPMainThread(JNIEnv *env,
                                                                       jobject jobj) {
    //1. 得到 jclass
    jclass jclz = env->GetObjectClass(jobj);
    
    //2. 得到 jmethod
    jmethodID jmethod = env->GetMethodID(jclz, "onSuccess", "(Ljava/lang/String;)V");


    //得到 jstring 
    char *msg = "Msg From C++ Thread";
    jstring jmsg = env->NewStringUTF(msg);


    //3. 调用函数
    env->CallVoidMethod(jobj, jmethod, jmsg);

    env->DeleteLocalRef(jmsg);

}

小结:通过以上示例代码,我们就可以实现在 Java 层调用 JNI 层函数执行完某一些操作之后,然后 JNI 层再告诉 Java 层具体的操作结果,也就是调用 Java 层的函数。

项目地址:
https://github.com/liaowjcoder/Jni4Android

记录于 2018年11月10日晚

你可能感兴趣的:(Android 在JNI主线程调用Java方法)