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、类型转换
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/返回类型定义
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的子类别包括jclass、jstring,、jarray(这些类称为局部性的对象参考),他们就算定义成static,也要利用函数:
gObj = env->NewGlobalRef(obj);将其赋值从而保持全局性
7、JNI线程模式的调用
8、利用C++回调来更新UI(Handler)
同步锁:(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();
……
}
转载于:https://my.oschina.net/u/262922/blog/297938