androidNDK开发之JNI学习

1、在工程目录下编译

   javah -classpath F:\eclipse\adt-bundle-windows-x86-201309017\sdk\platforms\android-19\android.jar;bin/classes com.example.jnithread.MainActivity

 

2、增加log信息的方法

   在.c文件中添加

   #define LOG_TAG "System.out.cpp"

   #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

   #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

   在配置mk文件增加

   #liblog.so libGLESv2.so

   LOCAL_LDLIBS += -llog

  e.g

  LOGD("x=%d",x);

3、类型转换

androidNDK开发之JNI学习 

Java类型

本地类型

描述

boolean

jboolean

C/C++8位整型

byte

jbyte

C/C++带符号的8位整型

char

jchar

C/C++无符号的16位整型

short

jshort

C/C++带符号的16位整型

int

jint

C/C++带符号的32位整型

long

jlong

C/C++带符号的64位整型

float

jfloat

C/C++32位浮点型

double

jdouble

C/C++64位浮点型

Object

jobject

任何Java对象,或者没有对应java类型的对象

Class

jclass

Class对象

String

jstring

字符串对象

Object[]

jobjectArray

任何对象的数组

boolean[]

jbooleanArray

布尔型数组

byte[]

jbyteArray

比特型数组

char[]

jcharArray

字符型数组

short[]

jshortArray

短整型数组

int[]

jintArray

整型数组

long[]

jlongArray

长整型数组

float[]

jfloatArray

浮点型数组

double[]

jdoubleArray

双浮点型数组

 

4、对象传递机制

Ø 假如类为c/c++类,并开始在c/c++程序建立:

返回对象以jlong 类型强制转换对象的指针值,从而将c/c++的对象返回到java中以long变量保存起来,以便后续工作回调c/c++中的对象。

e.g  

dataInCpp * data1=new dataIntCpp();

return (jlong)data1;

////////////////////////////////////////

jlong data1;

dataInCpp * data2 = (dataInCpp *)data1;

Ø 假如类为java类,通过c/c++程序创建

A、在c++中创建并返回给java程序

Jclass clazz = env->FindClass(com/example/jnithread/myData);

If(!clazz){

return NULL;

}

jmethodID constr = env->GetMethodID(clazz,<init>,()V);

if(!constr){

return;

}

jobject newObj = env->NewObject(clazz,constr);

if(!newObj){

return;

}

        return newObj;

 

java程序中直接用类型myData接收即可,无需用Object

    B、将c++中创建的java对象再传回给c++方法

jclass clazz = env->GetObjectClass(dataObject);

接下来和调用java类中函数一样如下所述

 

5、简单说明一下c++调用java函数:

Ø 非静态方法调用

jclass dpclazz = env->FindClass(com/example/jnithreads/MainActivity);

if(dpclazz==0){

LOGI(find class error);

return;

}

//去得到函数的信息 javap s com.example.jnithreads.MainActivity

jmethod method1 = env->GetMethodID(dpclazz,getNum,(参数)V);  

//获取非静态方法的ID

//V代表返回类型为void,也可(II)I,表示接收两个int方法返回int类型

//如果是String类型的参数写为(Ljava/lang/String;),如果返回类型为byte数组则写为[B

  If(method1==0){

LOGI(find method1 error);

Return;

}

env->CallVoidMethod(obj,method1);//Void表示返回类型为void

//int result = env->CallVoidMethod(obj,method1,3,5); 后面为参数

 

注:

1/返回类型定义

androidNDK开发之JNI学习 

2/如果要调用类似【hello.getBytes(gb2312);】则需要

   env->CallVoidMethod(obj,hello,method1,gb2312);//~要先转换为jstring

3/ byteArray->char *

  jsize len = env->GetArrayLength(byteArray);

  jbyte* ba = env->GetByteArrayElements(byteArray,JNI_FALSE);

  if(len>0){

char * rtn = (char *)malloc(len+1);

    memcpy(rtn,ba,len);

rth[len]=0;

}

env->ReleaseByteArrayElements(byteArray,ba,0);//释放掉内存空间

return rtn;

4/获取java对象的ID:

jfieldID field_a=env->GetFieldID(dpclazz,a,I);

int ma=(int)env->GetObjectField(obj,field_a);//调用以获得值

 

Ø 静态方法调用:

获取非静态方法的ID

jmethod methodID = env->GetStaticMethodID(dpclazz,getNum,(参数)V);  

调用静态方法:

env->CallStaticVoidMethod(dpclazz,mthodID,参数)

 

熟记:get 参数 clazz   call参数 obj,methodID 

             如果是static的话,call前面obj改为clazz

6、全局变量

  Jobject的子类别包括jclassjstring,jarray(这些类称为局部性的对象参考),他们就算定义成static,也要利用函数:

gObj = env->NewGlobalRef(obj);将其赋值从而保持全局性

7JNI线程模式的调用

androidNDK开发之JNI学习 

8、利用C++回调来更新UI(Handler)

androidNDK开发之JNI学习 

 同步锁:(java调用c++)

1、定义的时候:private native synchronized String execute(Object oSync);

进入函数资源调用时:env->MonitorEnter(syncObj);

释放时env->MonitorExit(syncObj);

上面讲的是不同线程情况下将对象传入C++程序,所以还是与线程安全有关

如果是在c++程序中的多线程,也一样。

多线程注意:

if (0 == gVm->AttachCurrentThread(&env, NULL))

{

gVm->DetachCurrentThread();

……

}

androidNDK开发之JNI学习 

 

 


转载于:https://my.oschina.net/u/262922/blog/297938