`
david_je
  • 浏览: 373875 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

如何在native代码里面回调java中的方法

 
阅读更多

            现在的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),他们分别在程序的开始和结束的时候调用。我们可以把一些初始化和释放的工作在这两个方法中完成。

 

   是不是很有意思?

        

 

分享到:
评论

相关推荐

    Android JNI多线程编程回调JAVA函数

    - 要实现native方法回调Java,可以在本地代码中调用`JNIEnv`指针提供的`CallVoidMethod`, `CallIntMethod`等函数,传入Java对象和方法ID,从而执行Java代码。 4. **线程间的通信和同步**: - 由于本地线程和Java...

    C回调java几种方法

    "C回调Java方法"是指从C代码中调用Java的方法,这通常通过Java Native Interface(JNI)实现。JNI是Java平台标准的一部分,它提供了一套接口让Java代码能够调用本地(非Java)代码,反之亦然。本文将详细探讨C回调...

    JNI层中创建的线程中回调java方法代码

    当我们需要在C/C++代码中执行Java方法或者在非Java线程中回调Java方法时,JNI就显得尤为重要。本教程将深入探讨如何在JNI层中创建线程并回调Java方法。 首先,我们需要理解JNI的基本概念。JNI是Java平台标准版的一...

    C++JNI多线程回调java

    本示例聚焦于"C++ JNI多线程回调Java",即在C++中创建多线程,并在这些线程中通过JNI回调Java代码。 首先,我们需要理解JNI的基本概念。JNI是一种接口,它定义了Java虚拟机(JVM)如何与本地代码(如C++)交互。这...

    jni编程c回调java的方法

    本篇文章将深入探讨如何在JNI中实现C代码回调Java的方法。 ### 1. JNI基础 JNI接口定义了一套C/C++的函数,这些函数在Java虚拟机(JVM)内部被调用。在Java代码中,我们可以通过`System.loadLibrary`来加载本地库...

    Android NDK开发——C回调Java中的方法

    本篇文章将详细介绍如何在Android NDK开发中实现C回调Java中的方法。 首先,了解NDK和JNI的基础概念是必要的。NDK是一套工具,提供了在Android平台上编译和运行C/C++代码的环境。而JNI是Java平台的标准接口,它允许...

    JNI调用C++代码和C++层回调java层 demo

    JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行...6. 在C++代码中通过JNI接口回调Java方法。 通过这样的方式,我们可以充分利用Java和C++的优点,实现跨语言的高效交互。

    JNI层创建的线程中回调java方法

    在`NativeThreadCallbackDemo`这个示例中,很可能包含了一个演示如何在JNI创建线程并回调Java方法的代码。通常,它会展示如何保存JNIEnv,如何启动本地线程,以及如何在该线程中安全地调用Java方法。通过分析和学习...

    android jni c回调java

    本教程将详细介绍如何在Android中使用JNI实现C语言回调Java的方法,包括有参无参、有无返回值以及静态非静态函数的不同情况。 1. **JNI基础概念** JNI是Java平台的标准组成部分,它提供了一套接口,使得Java代码...

    JNI调用及回调就(Java&C) 源码

    在Java中,我们定义一个带有`native`关键字的方法,这个方法的实现是在本地代码中完成的。然后,使用`javah`工具生成对应的C/C++头文件,这个头文件包含了Java方法的C/C++声明。接着,在C/C++代码中实现这个方法,...

    轻松学会JNI层多线程回调java方法

    多线程回调Java方法在JNI层实现,能够帮助我们优化程序执行效率,特别是在处理耗时操作如图像处理、音频视频解码等场景。 本文将深入探讨如何在JNI层实现多线程回调Java方法,以及如何解决在C/C++层多线程环境下...

    微信支付回调工具类

    回调工具类在这个流程中的作用是监听微信支付服务器的回调,接收到通知后,验证其真实性,然后处理支付结果。主要功能包括: - 验证回调数据的签名,确保信息未被篡改。 - 解析回调数据,获取支付状态、订单号等...

    jni回调Java层函数示例

    NI是Java Native Interface的缩写,是Java平台的重要特性,使得Java代码可以方便地与C/C++代码...本文主要给出一份示例代码(工程文件见附件),描述如何在Android的JNI层开启一个线程,并在线程中回调Java层的函数。

    JNI回调函数,java和c方法相互调用

    在C/C++代码中,我们需要实现对应的函数,这个函数将被Java中的native方法调用。 3. **C/C++调用Java**:实现C/C++回调Java方法的关键在于`RegisterNatives`函数,它允许我们注册一组本地方法,每个方法都可以直接...

    Android JNI native调用 java层demo TESTJNI.zip

    本文将深入探讨在Android中如何使用JNI,特别是如何从C++ native代码调用Java层的类、方法、属性以及接口,同时涉及线程回调接口的实现。 首先,我们需要了解JNI的基本结构。一个典型的JNI应用会包含Java源文件、C/...

    亲测可用,java 成功调用dll函数。包含调用回调函数,springboot版本。最近由于公司业务需要,要调用dll文件,用JNA调用。

    在Java通过JNA调用DLL时,如果DLL函数需要一个回调函数作为参数,那么Java需要定义一个接口,该接口的方法将作为回调函数的实现,JNA会处理这个接口的调用转换。 4. **Spring Boot**:Spring Boot是基于Spring框架...

    jni的回调使用

    JNI为Java应用程序提供了调用本地方法(即C/C++代码)的能力,同时也允许本地代码回调Java方法。这个过程涉及到几个关键步骤: 1. **声明本地方法**:在Java类中,使用`native`关键字声明一个本地方法,但不提供...

    微信支付源码 java网页微信支付 java网页Native微信支付源码

    在这个Java网页Native微信支付源码中,我们可以深入理解微信支付的API调用、二维码生成以及支付回调处理等关键流程。 1. **微信支付接口调用**: - 微信支付提供了多种接口供开发者使用,如统一下单接口(Unified ...

    Android APP 用interface 接口的形式对jni进行回调,实例测试

    在Android应用开发中,JNI(Java Native Interface)是Java与本地代码交互的一种方式,它允许开发者使用C++、C等语言编写部分性能敏感或需要利用硬件特性功能的代码。本实例测试主要探讨如何通过Java接口(interface...

    ReactNative调原生Android代码

    在实际项目中,你可能会传递参数、处理回调,甚至封装更复杂的原生模块。理解这个过程对于提升React Native应用的功能性和性能至关重要,因为它使你能够充分利用原生平台的能力。通过这种方式,你可以编写出更健壮、...

Global site tag (gtag.js) - Google Analytics