Android JNI参数传递

转载 2016年08月29日 16:54:11

Java中调用native函数传递的参数是Java数据类型,到了JNI层需进行数据类型转换,基本数据类型是在前面加个j,如int——>jint,应用数据类型除了基本数据类型的数据、Class、String和Throwable外,其余所有Java对象的数据类型在JNI中都用jobject表示。

//Java层com.xxx.yyy包MyJni.java中的jnitest有三个参数
jnitest(String path, String name, MyJni mj);
//JNI层对应的函数的后三个参数与jnitest的参数对应
com_xxx_yyy_MyJni_jnitest(JNIEnv *env, jobject thiz, jstring path, jstring name, jobject mj);

若对象类型都用就object表示,就好比是native层的void* 类型一样。第二个参数就object代表Java层的实例对象,如果Java层是static函数,则这个参数将是jclass,表示在调用哪个Java Class的静态函数。

JNIEnv介绍

JNIEnv是一个与线程相关的代表JNI环境的结构体,内部结构如图:

这里写图片描述

从上图可知JNIEnv提供了一些JNI系统函数:

  • 调用Java的函数
  • 操作jobejct对象等很多事情

每个线程都有一个JNIEnv,由于线程相关,所以一个线程不能使用另一个线程的JNIEnv结构体。JNIEnv是native函数转换成JNI层函数后有虚拟机传进来的,但当后台线程收到一个网络消息,且需有native层函数主动回调Java层函数时,JNIEnv如何传递?

这就要用到JavaVM,它是虚拟机在JNI层的代表,如下:

//全进程只有一个JavaVM对象,可保存且在任何地方都可使用
jint JNI_OnLoad(JavaVM* vm, void* reserved);

而JavaVM 和 JNIEnv的关系如下:

  • 调用JavaVM的AttachCurrentThread函数,就可得到这个线程的JNIEnv结构体,即可在后台回调Java函数。
  • 在后台线程退出前,需调用JavaVM的DetachCurrentThread函数释放对应的资源。

通过JNIEnv操作jobject

Java引用类型除了少数几个外,其余在JNI层都会用jobject来表示对象的数据类型,操作jobject的本质是操作Java对象的成员变量和成员函数。
jfieldID 和 jmethodID 介绍
JNI规则中用jfieldID 和 jmethodID表示Java类的成员变量和成员函数,可通过JNIEnv的函数得到:
jfieldID GetFieldID(jclass clazz, const char *name, const char *sig);
jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);
其中,jclass表示Java类,name表示成员函数或成员变量的名字,sig为这个函数和变量的签名信息。使用方法如下:
MyJni(JNIEnv *env, jobject mj)......
{
  //先找到com.xxx.yyy.MyJni类在JNI层中对应的jclass实例。
  jclass myJniInterface = env->FindClass("com.xxx.yyy.MyJni");
  //取出MyJni类中函数jnitest的jMethodID。
  mMyJniMethodID = env->GetMethodID(myJniInterface, "jnitest", "(Ljava/lang/String;JJ)V");
  //取出MyJni类中函数jnitest1的jMethodID。
  mJniTestMethodID = env->GetMethodID(myJniInterface, "jnitest1", 
  "(Ljava/lang/String;Ljava/lang/String;)V");
如果每次操作jobject前都去查询jmethodID或jfieldID,将会影响程序的运行效率,故在初始化时可取出ID并保存起来供后续使用。

使用jfieldID 和 jmethodID

实例代码如下:
virtual bool myjni(const char* path, long long lastModified, long long fileSize)
{
  jstring pathstr;
  if ((pathStr = mEnv->NewStringUTF(path)) == NULL)
      return;
  /*
  调用JNIEnv的CallVoidMethod函数,注意CallVoidMethod的参数:
  第一个是MyJni的jobject对象,
  第二个是函数myjni的jmethodID,后面是Java中myjni的参数
  */
  mEnv->CallVoidMethod(mClient, mMyJniMethodID, pathStr, lastModified, fileSize);
  mEnv->DeleteLocalRef(pathStr);
  return (!mEnv->ExceptionCheck());
通过JNIEnv输出CallVoidMethod,再把jobject、jMethodID和对应的参数传进去,JNI层就能调用Java对象的函数。
实际上JNIEnv输出一系列类似CallVoidMethod的函数,形式如下:
NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...)
其中type对应Java函数的返回值类型,例如CallIntMethod、CallVoidMethod等。
上面是针对非static函数,如果调用Java的static函数,则用JNIEnv输出的CallStatic< Type>Method系列函数。
通过jfieldID操作jobject的成员变量,如下:
//获得filedID可调用Get<type>Field系列函数获取jobject对应的成员变量值
nativeType Get<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID)
//或调用Set<type>Field系列函数设置jobject对应的成员变量值
void Set<type>Field(JNIEnv *env, jobject obj, jfield fieldID, NativeType value)

JNI类型签名介绍

static JNINativeMethod gMethods[] = {
    ......
    {
    "processFile"
    "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V", 
    (void*)com_xxx_yyy_MyJni
    },
    ......
    }
代码中字符串”(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V”是Java中对应函数的签名信息,有参数类型和返回值类型共同组成。Java支持函数重载,可定义同名但不同参数的函数,进根据函数名无法找到具体函数,故JNI技术中将参数类型和返回值类型作为函数的签名信息。
JNI规范定义的函数签名信息格式:
(参数1类型标示参数2类型标示...参数n类型标示)返回值类型标示
“(Ljava/lang/String;Ljava/lang/String;Landroid/media/MyJni;)V”,其中括号内是参数类型的标识,最右边是返回值类型的标识,void类型对应的标识是V。当参数的类型是引用类型时,其格式是“L包名;”,其中包名中的“.”换成“/”。Ljava/lang/String表示是一个Java的String类型。

android之JNI参数传递

android之JNI参数传递
  • boise
  • boise
  • 2016年06月08日 09:41
  • 794

Android Studio下JNI编程2(接上篇,详细讲解java与c层互传参数)

Android Studio下JNI环境搭建、编译、运行等可以参考: http://blog.csdn.net/huangximin1990/article/details/50441400 ...
  • huangximin1990
  • huangximin1990
  • 2016年03月09日 00:18
  • 1063

android之JNI参数传递 (Java方法调用)

从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C...
  • u013378580
  • u013378580
  • 2016年08月26日 14:23
  • 654

Android操作JNI函数以及复杂对象传递

在掌握了JNI函数的使用和相关类型的映射后,以及知晓何利用javah工具生成对应的jni函数以及如何生成动态     链接库 (windos下就是.dll库,Linux就是.so库了,不懂在Wi...
  • jake9602
  • jake9602
  • 2014年02月26日 10:38
  • 956

android(NDK+JNI)---JNI字符串参数传递与返回值

转载请注明出处! 原文地址链接:http://blog.csdn.net/zgyulongfei/article/details/7409441   在编程的时候我们不仅需要使用无参...
  • u014737138
  • u014737138
  • 2016年04月12日 16:36
  • 1412

JNI中参数的传递与操作

JNI的所有的本地方法的第一个参数都是指向JNIEnv结构的。这个结构是用来调用JNI函数的。第二个参数jclass/jobject的意义,要看方法是不是静态的(static)或者实例(Instanc...
  • hetangbian
  • hetangbian
  • 2016年12月05日 14:38
  • 2274

Android NDK 开发(二)JNI 传递参数和返回值

前言我们在使用 JNI 时最常问到的是 JAVA 和 C/C++之间如何传递数据,以及数据类型之间如何 互相映射。我们从整数等基本类型和数组、字符串等普通的对象类型开始讲述。至于如何传递任意对象,将在...
  • u011974987
  • u011974987
  • 2016年10月06日 20:06
  • 4741

《Android JNI》02 对java传进来的整形参数进行操作并返回

使用NDK创建Jni工程 对java传进来的整形参数进行操作并返回 使用NDK创建Jni工程 新建一个Android工程并右键添加native support library 然后输入你想生成库的...
  • HERGhost
  • HERGhost
  • 2016年04月23日 11:25
  • 511

Android JNI 传递对象

jni初步入门后,在传递数据的时候,遇到一个需求:有多个数据需要在java与c代码之间进行传递。如果都做为函数参数传入,则函数很长很难看,并且多个数据的返回也不好实现。所以想到了把数据打包后传递这在C...
  • lintax
  • lintax
  • 2016年06月25日 17:25
  • 1868

Android使用NDK---函数参数传递-基本类型和数组

参考链接:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/19/2145486.html 数据传输可分为 基本数据类型传输 和 引用数据类...
  • wishchin
  • wishchin
  • 2015年07月01日 16:41
  • 1470
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android JNI参数传递
举报原因:
原因补充:

(最多只允许输入30个字)