zoukankan      html  css  js  c++  java
  • [置顶] Android JNI必须掌握的五点

     

    1:JNI是什么?

     

    Java NativeInterface(JNI)是Java提供的一个很重要的特性。它使得用诸如C/C++等语言编写的代码可以与运行于Java虚拟机(JVM)中的 Java代码集成。有些时候,Java并不能满足你的全部开发需求,比如你希望提高某些关键模块的效率,或者你必须使用某个以C/C++等Native语 言编写的程序库;此时,JNI就能满足你在Java代码中访问这些Native模块的需求。JNI的出现使得开发者既可以利用Java语言跨平台、类库丰 富、开发便捷等特点,又可以利用Native语言的高效。

     

    2:JNI和JVM什么关系?

    JNI是JVM实现中的一部分,因此Native语言和Java代码都运行在JVM的宿主环境(Host Environment)。此外,JNI是一个双向的接口:开发者不仅可以通过JNI在Java代码中访问Native模块,还可以在 Native代码中嵌入一个JVM,并通过JNI访问运行于其中的Java模块。可见,JNI担任了一个桥梁的角色,它将JVM与Native模块联系起来,从而实现了Java代码与Native代码的互访。在OPhone上使用Java虚拟机是为嵌入式设备特别优化的Dalvik虚拟机。每启动一个应 用,系统会建立一个新的进程运行一个Dalvik虚拟机,因此各应用实际上是运行在各自的VM中的。Dalvik VM对JNI的规范支持的较全面,对于从JDK 1.2到JDK 1.6补充的增强功能也基本都能支持。

     

    开发者在使用JNI之前需要充分了解其优缺点,以便合理选择技术方案实现目标。JNI的优点前面已经讲过,这里不再重复,其缺点也是显而易见的:由于Native模块的使用,Java代码会丧失其原有的跨平台性和类型安全等特性。此外,在JNI应用中,Java代码与Native代码运行于同一个进程空间内;对于跨进程甚至跨宿主环境的Java与Native间通信的需求,可以考虑采用socket、Web Service等IPC通信机制来实现。

     

     

    3:JNI在JAVE和c++中互操作性;

         a:java和c++的基本调用:

         完整的例子:  http://www.2cto.com/kf/201203/123039.html

         b:JNIhelper的概念和用法:

        完整的例子:http://codingnow.cn/cocos2d-x/992.html,就是编译的时候,会出现编译的error,想调试的哥们,try一下;问题不大;

         c:独立JNIhelper的使用:

         http://blog.csdn.net/penguu8/article/details/9629627

     

    4:JNI的编译

     

         Android.mk的编译配置:

         http://blog.csdn.net/penguu8/article/details/9667301

     

         编译的基本命令:

         http://blog.csdn.net/penguu8/article/details/9667333

     

     

    5: JNI用法品读

     

       (1).andorid CPP调用java函数和访问其成员:

    原理 => CPP代码找到java的那个class里面的函数的入口地址,然后在CPP代码中调用java代码

     

    步骤1) 用FindClass()函数找到该java类(如android.os.Binder)的实例对象的引用:

    jclass clazz =env->FindClass(kBinderPathName) =env->FindClass("android.os.Binder")

     

    步骤2) 用GetFieldID()函数获取到要访问的域(field: 实际上就是该java class中的某个成员变量的名字)的ID:

    gBinderOffsets.mObject= env->GetFieldID(clazz, "mObject", "I") // mObject为java class "Binder"里的一个成员变量

    -> 注意,这里将要访问的那个java对象的成员mObject的ID保存到了全局变量gBinderOffsets.mObject中,这样做的前提和优点如下:

    前提: android里面,每个java进程中只允许有一个java虚拟机(sun公司原始的java架构中,一个进程中可以有多个java虚拟机)

    优点: 除了第一次,以后每次要访问该java对象的成员mObject就非常快了(不用再去FindClass()和GetFieldID())

     

    步骤3) 用GetMethodID()函数获取到要访问的方法(Method: 实际上就是该java class中的某个成员函数的名字)的ID:

    gBinderOffsets.mExecTransact= env->GetMethodID(clazz, "execTransact", "(IIII)Z") //execTransact为java class "Binder"里的一个成员函数

     

    步骤4) 用类似于GetIntField()的函数获取到该java对象的那个域(即成员)的值:

    IBinder* target =(IBinder*)env->GetIntField(obj,gBinderProxyOffsets.mObject)

        // 获取javaandroid.os.Binder类型对象里面的成员mObject的值 


    步骤5) 用类似于CallBooleanMethod()的函数调用到该java对象的那个成员函数:

    jboolean res =env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code,(int32_t)&data, (int32_t)reply, flags)

     

    (2).android java调用CPP函数:

     

    原理 => 相当于java的那个class里面有的函数使用CPP代码来实现了

    1)通过结构JNINativeMethod描述java代码调用函数和CPP函数的对应关系:

    typedef struct {

    const char* name; //java代码调用CPP函数的入口

    const char*signature; // CPP函数的返回值

    void* fnPtr; // CPP的函数名

    } JNINativeMethod;

    => 例如: java代码通过IBinder.transact()来调用CPP的函数android_os_BinderProxy_transact()

    {"transact","(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z",(void*)android_os_BinderProxy_transact},

     

    2)将CPP函数注册到java的某个class中: 使用函数AndroidRuntime::registerNativeMethods()来注册

    => 这之后,java代码就可以调用CPP函数了

     

    3)java代码调用CPP函数方法:

    IBinder.transact()

     

    总结其原理:C/C++要调用JAVA程序,必须先加载JAVA虚拟机,由JAVA虚拟机解释执行class文件。为了初始化JAVA虚拟机,JNI提供了一系列的接口函数,通过这些函数方便地加载虚拟机到内存中。     

         

         

     

     


  • 相关阅读:
    Linux命令应用大词典-第11章 Shell编程
    Kubernetes 学习12 kubernetes 存储卷
    linux dd命令
    Kubernetes 学习11 kubernetes ingress及ingress controller
    Kubernetes 学习10 Service资源
    Kubernetes 学习9 Pod控制器
    Kubernetes 学习8 Pod控制器
    Kubernetes 学习7 Pod控制器应用进阶2
    Kubernetes 学习6 Pod控制器应用进阶
    Kubernetes 学习5 kubernetes资源清单定义入门
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3228640.html
Copyright © 2011-2022 走看看