1. C++ 全局調(diào)用Java方法
1.1 C++主線程調(diào)用Java方法
在 Android C++多線程-創(chuàng)建子線程中演示了在 Java 層調(diào)用 native 層的方法,但是如何在 native 層去調(diào)用 Java 層的方法呢?
下面這個(gè)類,我們想在調(diào)用 callJavaMethodOnCPPMainThread 方法之后,然后在 native 層回調(diào) JniThreadDemo 的 onSuccess 的方法。
public class JniThreadDemo {
private static final String TAG = JniThreadDemo.class.getSimpleName();
static {
System.loadLibrary("native-thread-lib");
}
//在主線程中調(diào)用 onSuccess 方法
public native void callJavaMethodOnCPPMainThread();
public void onSuccess(String msg) {
Log.i(TAG, "JNI 回調(diào) Java層 onSuccess 方法:" + msg);
}
}
實(shí)際的調(diào)用函數(shù)
public void callJavaMethodOnCppMainThread(View view) {
JniThreadDemo jniThreadDemo = new JniThreadDemo();
//在主線程調(diào)用
jniThreadDemo.callJavaMethodOnCPPMainThread();
}
上面演示的只是調(diào)用了 jniThreadDemo.callJavaMethodOnCPPMainThread 函數(shù),下面我們來看看如何在 native 層去回調(diào) onSuccess 函數(shù)的。
1.2 native 回調(diào) Java 層函數(shù)的過程
這個(gè)過程類似于 Java 的反射過程,例如下面的例子
public class JniThreadDemo {
public void onSuccess(String msg) {
System.out.println("onSuccess invoke.."+ msg);
}
public static void main(String[] args) {
try {
Class<JniThreadDemo> clz = JniThreadDemo.class;
Method method = clz.getMethod("onSuccess", String.class);
JniThreadDemo jniThreadDemo = clz.newInstance();
method.invoke(jniThreadDemo, "反射");
} catch (Exception e) {
e.printStackTrace();
}
}
}
下面來看一下,Jni 時(shí)如何調(diào)用 Java 層的函數(shù)的。
1.2.1 獲取到 jclass
根據(jù) jobject 獲取到 jclass
jclass jclz = env->GetObjectClass(instance);
1.2.2 獲取到 jmethodid
因?yàn)橐卣{(diào) Java 層的 onSuccess 函數(shù),所以需要在這里定義具體要調(diào)用的函數(shù)名字和函數(shù)簽名,具體如何獲取函數(shù)簽名,請點(diǎn)擊JNI函數(shù)簽名來了解
jmethodID jmethod = env->GetMethodID(jclz, "onSuccess", "(Ljava/lang/String;)V");
1.2.3 調(diào)用 Java 方法
jenv->CallVoidMethod(jobj, jmid, code, jmsg)
下面是 C++ 的全部代碼
//在 c++ 主線程調(diào)用 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. 調(diào)用函數(shù)
env->CallVoidMethod(jobj, jmethod, jmsg);
env->DeleteLocalRef(jmsg);
}
小結(jié):通過以上示例代碼,我們就可以實(shí)現(xiàn)在 Java 層調(diào)用 JNI 層函數(shù)執(zhí)行完某一些操作之后,然后 JNI 層再告訴 Java 層具體的操作結(jié)果,也就是調(diào)用 Java 層的函數(shù)。
項(xiàng)目地址:
https://github.com/liaowjcoder/Jni4Android
記錄于 2018年11月10日晚