现在的Android应用,越来越多开始使用JNI调用了,把底层的复杂运算交给C/C++来完成,然后通过JNI来完成java与C/C++的连接。
在我开发一个这样的应用的过程中,遇到了一个回调的问题。除了在java层调用C的实现,有时候也需要在C层调用java的方法。比如,在C层实现的事件处理器需要在事件发生时,上抛事件,告诉java层。
这个过程和java调用C不一样,java中的调用是声明了native关键字的方法,在C层去实现他的方式来调用,他可以获得JNI interface 的指针(就是JNIEnv),可以获得虚拟机的上下文环境。而C中调用java中的方法是没有办法获得这些东西,必须通过java虚拟机来获得。Java提供了满足这种需求的API(Invocation API:http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html)。
Invocation API允许应用区加载Java虚拟机到任意一个native应用,比如:
#include <jni.h> /* where everything is defined */ ... JavaVM *jvm; /* denotes a Java VM */ JNIEnv *env; /* pointer to native method interface */ JDK1_1InitArgs vm_args; /* JDK 1.1 VM initialization arguments */ vm_args.version = 0x00010001; /* New in 1.1.2: VM version */ /* Get the default initialization arguments and set the class * path */ JNI_GetDefaultJavaVMInitArgs(&vm_args); vm_args.classpath = ...; /* load and initialize a Java VM, return a JNI interface * pointer in env */ JNI_CreateJavaVM(&jvm, &env, &vm_args); /* invoke the Main.test method using the JNI */ jclass cls = env->FindClass("Main"); jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V"); env->CallStaticVoidMethod(cls, mid, 100); /* We are done. */ jvm->DestroyJavaVM();
这是一个C++中获得虚拟机的example,是在JDK 1.1中实现的,现在已经跑不通了,经供参考,但是里面得到虚拟机原理是一样的。
它用到了3个方法: Create VM,Attaching VM,Unloading VM.
JNI_CreateJavaVM() 方法用来加载和初始化一个java虚拟机并且返回JNI接口的指针(JNIEnv), 这个线程被看做是主线程。
JNIEnv是在当前线程中是合法的,如果其他的线程去访问java虚拟机,他必须调用一下AttachCurrentThread()方法,把自己附属到VM中才能获得JNIEnv。一旦调用成功,native的线程就像一个普通的java线程运行在native的线程中(native中的线程都是Linux线程,由内核调用执行)。native线程仍然连接到VM,直到它调用DetachCurrentThread()来分离。
主线程不能从VM中分离自己,必须调用DestroyJavaVM()方法去卸载整个VM。
有了这些概念,就很容易理解整个问题了。来看一下我们的主要代码调用:
//declare java VM and jobject JavaVM* globalVM; jobject globalObj; //Get VM and JNIEnv at a native implemention method statement JNIEXPORT jint JNICALL Java_com_ericsson_mstv_client_upnp_api_UPnPCtrlPointNative_ctrlPointStart( JNIEnv *env, jobject jObj) { globalObj = (*env)->NewGlobalRef(env, jObj); (*env)->GetJavaVM(env, &globalVM); return startCtrlPoint(uPnPCallback,NULL); } //event handler void callback(....){ JNIEnv *env; if(!globalVM || !globalObj){ return; } int envState = (*globalVM)->GetEnv(globalVM, (void **) &env, JNI_VERSION_1_6); if (envState == JNI_EDETACHED) { envState = (*globalVM)->AttachCurrentThread(globalVM, &env, NULL); if (envState != 0) { //something log print return; } } else if (envState == JNI_EVERSION) { //something log print return; } //JNI data structure conversion ........ (*globalVM)->DetachCurrentThread(globalVM); } JNIEXPORT jint JNICALL Java_com_ericsson_mstv_client_upnp_api_UPnPCtrlPointNative_ctrlPointStop( JNIEnv *env, jobject jObj) { (*env)->DeleteGlobalRef(env, globalObj); globalVM = NULL; return stopCtrlPoint(); }
在这里用到了两个native方法,因为在在我们项目中的lifecycle的start和stop阶段调用,所以就把VM的一些逻辑放到里面来完成。其实Invocation API中提供了两个方法:jint JNI_OnLoad(JavaVM *vm, void *reserved) 和void JNI_OnUnload(JavaVM *vm, void *reserved),他们分别在程序的开始和结束的时候调用。我们可以把一些初始化和释放的工作在这两个方法中完成。
是不是很有意思?
相关推荐
- 要实现native方法回调Java,可以在本地代码中调用`JNIEnv`指针提供的`CallVoidMethod`, `CallIntMethod`等函数,传入Java对象和方法ID,从而执行Java代码。 4. **线程间的通信和同步**: - 由于本地线程和Java...
"C回调Java方法"是指从C代码中调用Java的方法,这通常通过Java Native Interface(JNI)实现。JNI是Java平台标准的一部分,它提供了一套接口让Java代码能够调用本地(非Java)代码,反之亦然。本文将详细探讨C回调...
当我们需要在C/C++代码中执行Java方法或者在非Java线程中回调Java方法时,JNI就显得尤为重要。本教程将深入探讨如何在JNI层中创建线程并回调Java方法。 首先,我们需要理解JNI的基本概念。JNI是Java平台标准版的一...
本示例聚焦于"C++ JNI多线程回调Java",即在C++中创建多线程,并在这些线程中通过JNI回调Java代码。 首先,我们需要理解JNI的基本概念。JNI是一种接口,它定义了Java虚拟机(JVM)如何与本地代码(如C++)交互。这...
本篇文章将深入探讨如何在JNI中实现C代码回调Java的方法。 ### 1. JNI基础 JNI接口定义了一套C/C++的函数,这些函数在Java虚拟机(JVM)内部被调用。在Java代码中,我们可以通过`System.loadLibrary`来加载本地库...
本篇文章将详细介绍如何在Android NDK开发中实现C回调Java中的方法。 首先,了解NDK和JNI的基础概念是必要的。NDK是一套工具,提供了在Android平台上编译和运行C/C++代码的环境。而JNI是Java平台的标准接口,它允许...
JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行...6. 在C++代码中通过JNI接口回调Java方法。 通过这样的方式,我们可以充分利用Java和C++的优点,实现跨语言的高效交互。
在`NativeThreadCallbackDemo`这个示例中,很可能包含了一个演示如何在JNI创建线程并回调Java方法的代码。通常,它会展示如何保存JNIEnv,如何启动本地线程,以及如何在该线程中安全地调用Java方法。通过分析和学习...
本教程将详细介绍如何在Android中使用JNI实现C语言回调Java的方法,包括有参无参、有无返回值以及静态非静态函数的不同情况。 1. **JNI基础概念** JNI是Java平台的标准组成部分,它提供了一套接口,使得Java代码...
在Java中,我们定义一个带有`native`关键字的方法,这个方法的实现是在本地代码中完成的。然后,使用`javah`工具生成对应的C/C++头文件,这个头文件包含了Java方法的C/C++声明。接着,在C/C++代码中实现这个方法,...
多线程回调Java方法在JNI层实现,能够帮助我们优化程序执行效率,特别是在处理耗时操作如图像处理、音频视频解码等场景。 本文将深入探讨如何在JNI层实现多线程回调Java方法,以及如何解决在C/C++层多线程环境下...
回调工具类在这个流程中的作用是监听微信支付服务器的回调,接收到通知后,验证其真实性,然后处理支付结果。主要功能包括: - 验证回调数据的签名,确保信息未被篡改。 - 解析回调数据,获取支付状态、订单号等...
NI是Java Native Interface的缩写,是Java平台的重要特性,使得Java代码可以方便地与C/C++代码...本文主要给出一份示例代码(工程文件见附件),描述如何在Android的JNI层开启一个线程,并在线程中回调Java层的函数。
在C/C++代码中,我们需要实现对应的函数,这个函数将被Java中的native方法调用。 3. **C/C++调用Java**:实现C/C++回调Java方法的关键在于`RegisterNatives`函数,它允许我们注册一组本地方法,每个方法都可以直接...
本文将深入探讨在Android中如何使用JNI,特别是如何从C++ native代码调用Java层的类、方法、属性以及接口,同时涉及线程回调接口的实现。 首先,我们需要了解JNI的基本结构。一个典型的JNI应用会包含Java源文件、C/...
在Java通过JNA调用DLL时,如果DLL函数需要一个回调函数作为参数,那么Java需要定义一个接口,该接口的方法将作为回调函数的实现,JNA会处理这个接口的调用转换。 4. **Spring Boot**:Spring Boot是基于Spring框架...
JNI为Java应用程序提供了调用本地方法(即C/C++代码)的能力,同时也允许本地代码回调Java方法。这个过程涉及到几个关键步骤: 1. **声明本地方法**:在Java类中,使用`native`关键字声明一个本地方法,但不提供...
在这个Java网页Native微信支付源码中,我们可以深入理解微信支付的API调用、二维码生成以及支付回调处理等关键流程。 1. **微信支付接口调用**: - 微信支付提供了多种接口供开发者使用,如统一下单接口(Unified ...
在Android应用开发中,JNI(Java Native Interface)是Java与本地代码交互的一种方式,它允许开发者使用C++、C等语言编写部分性能敏感或需要利用硬件特性功能的代码。本实例测试主要探讨如何通过Java接口(interface...
在实际项目中,你可能会传递参数、处理回调,甚至封装更复杂的原生模块。理解这个过程对于提升React Native应用的功能性和性能至关重要,因为它使你能够充分利用原生平台的能力。通过这种方式,你可以编写出更健壮、...