JNI

使用JNI的原则

总之,只有当你必须在同一进程中调用本地代码时,再使用JNI。

1、JAVA程序和本地程序使用TCP/IP或者IPC进行交互。

2、当用JAVA程序连接本地数据库时,使用JDBC提供的API。

3、JAVA程序可以使用分布式对象技术,如JAVA IDL API。

JNIEnv

JNIEnv 概念 : 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ;

JNIEnv 与 JavaVM :

注意区分这两个概念;

– JavaVM : JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局只有一个;

– JNIEnv : JavaVM 在线程中的代表, 每个线程都有一个, JNI 中可能有很多个JNIEnv;

JNIEnv 作用 :

– 调用 Java 函数 : JNIEnv 代表 Java 运行环境, 可以使用 JNIEnv 调用 Java 中的代码;

– 操作 Java 对象 : Java 对象传入 JNI 层就是 Jobject 对象, 需要使用 JNIEnv 来操作这个 Java 对象;
JNIEnv 体系结构

线程相关 : JNIEnv 是线程相关的, 即 在 每个线程中 都有一个 JNIEnv 指针, 每个JNIEnv 都是线程专有的, 其它线程不能使用本线程中的 JNIEnv, 线程 A 不能调用 线程 B 的 JNIEnv;

JNI 例子:
  1. Java 层
   private native String printJNI(String inputStr);
  1. 生成文件:com_android_HelloWorld.h

到classes一级目录:/HelloWorld/bin/classes/

执行如下命令:

  javah com.android.HelloWorld

  生成文件:com_android_HelloWorld.h

  1. 实现JNI原生函数源文件:

新建com_android_HelloWorld.c文件:

定义OnLoad
OnLoadJava_com_android_HelloWorld_printJNI
  1. 编译生成so库

      编译com_android_HelloWorld.c成so库可以和app一起编译,也可以都单独编译。
      
      

参数转换
1. 如何将java传入的String参数转换为c的char*,然后使用?

java传入的String参数,在c文件中被jni转换为jstring的数据类型,

//在c文件中声明
char* test;
test = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);
//注意:test使用完后,通知虚拟机平台相关代码无需再访问:
(*env)->ReleaseStringUTFChars(env, jstring, test);
2.将c中获取的一个char*的buffer传递给java?

这个char*如果是一般的字符串的话,作为string传回去就可以了。如果是含有’\0’的buffer,最好作为bytearray传出,因为可以制定copy的length,如果copy到string,可能到’\0’就截断了。

unsigned char buffer[256];
int i=0;
for(i=0;i<256;i++)
    buffer[i] = i;
//new一个byte数组
jbyteArray array = (*env)->NewByteArray(env,256);
//拷贝
(*env)->SetByteArrayRegion(env, array, 0, 256, buffer);
3. char* 和jstring互转

GetStringUTFChars

NewStringUTF

JNIEXPORT jstring JNICALL Java_com_explorer_jni_SambaTreeNative_getDetailsBy    
(JNIEnv *env, jobject jobj, jstring pc_server, jstring server_user, jstring server_passwd)    
{    
        const char *pc = env->GetStringUTFChars(pc_server, NULL);    
        const char *user = env->GetStringUTFChars(server_user, NULL);    
        const char *passwd = env->GetStringUTFChars(server_passwd, NULL);    
        const char *details = smbtree::getPara(pc, user, passwd);    
        jstring jDetails = env->NewStringUTF(details);    
        return jDetails;    
}    
4. 传对象到JNI调用
   jclass stu_cls = env->GetObjectClass(obj_stu); //或得Student类引用 
 jfieldID ageFieldID = env->GetFieldID(stucls,"age","I"); //获得得Student类的属性id     
  jfieldID nameFieldID = env->GetFieldID(stucls,"name","Ljava/lang/String;"); // 获得属性ID    

  jint age = env->GetIntField(objstu , ageFieldID);  //获得属性值    
  jstring name = (jstring)env->GetObjectField(objstu , nameFieldID);//获得属性值    

  const char * c_name = env->GetStringUTFChars(name ,NULL);//转换成 char *    

  string str_name = c_name ;     
  env->ReleaseStringUTFChars(name,c_name); //释放引用 
5. 回调Java层方法
jstring str = NULL;    

  jclass clz = env->FindClass("cc/androidos/jni/JniTest");    
  //获取clz的构造函数并生成一个对象    
  jmethodID ctor = env->GetMethodID(clz, "<init>", "()V");    
  jobject obj = env->NewObject(clz, ctor); 
// 如果是数组类型,则在类型前加[,如整形数组int[] intArray,则对应类型为[I,整形数组String[] strArray对应为[Ljava/lang/String;    
  jmethodID mid = env->GetMethodID(clz, "sayHelloFromJava", "(Ljava/lang/String;II[I)I");   
 jint javaIndex = env->CallIntMethod(obj, mid, str1, index1, index2, testIntArray);  
Java 类型本地类型描述
booleanjbooleanC/C++8位整型
bytejbyteC/C++带符号的8位整型
charjcharC/C++无符号的16位整型 (char 在java中是2个字节。java采用unicode,2个字节(16位)来表示一个字符)
shortjshortC/C++带符号的16位整型
intjintC/C++带符号的32位整型
longjlongC/C++带符号的64位整型e
floatjfloatC/C++32位浮点型
doublejdoubleC/C++64位浮点型
Objectjobject任何Java对象,或者没有对应java类型的对象
ClassjclassClass对象
Stringjstring字符串对象
Object[]jobjectArray任何对象的数组
boolean[]jbooleanArray布尔型数组
byte[]jbyteArray比特型数组
char[]jcharArray字符型数组
short[]jshortArray短整型数组
int[]jintArray整型数组
long[]jlongArray长整型数组
float[]jfloatArray浮点型数组
double[]jdoubleArray双浮点型数组
Java 类型符号
booleanZ
byteB
charC
shortS
intI
longJ
floatF
doubleD
voidV
objects对象L类名
Arrays数组[数组类型
methods方法(参数类型)返回类型
StringLjava/lang/String;
int[ ][I
float[ ][F
Object[ ][Ljava/lang/Object;
int [ ][ ]其描述符为[[I
float[ ][ ]其描述符为[[F
Java层方法JNI函数签名
String test ( )Ljava/lang/String;
int f (int i, Object object)(ILjava/lang/Object;)I
void set (byte[ ] bytes)([B)V
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值