AndroidNDK开发之JNI学习

androidNDK开发之JNI学习

1、在工程目录下编译

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文件中添加

1
2
3
4
5
#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文件增加

1
2
3
#liblog.so libGLESv2.so
LOCAL_LDLIBS += -llog

e.g

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

3、类型转换

image_mark

4、对象传递机制

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

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

e.g

1
2
3
4
5
6
7
8
9
dataInCpp * data1=new dataIntCpp();
return (jlong)data1;
////////////////////////////////////////
jlong data1;
dataInCpp * data2 = (dataInCpp *)data1;

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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++方法

1
jclass clazz = env->GetObjectClass(dataObject);

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

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

非静态方法调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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”);】则需要

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

3/ byteArray->char *

1
2
3
4
5
6
7
8
9
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为:

1
2
jfieldID field_a=env->GetFieldID(dpclazz,”a”,”I”);
int ma=(int)env->GetObjectField(obj,field_a);//调用以获得值

静态方法调用:

获取非静态方法的ID:

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

调用静态方法:

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

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

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

6、全局变量

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

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

7、JNI线程模式的调用

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

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

1、定义的时候:

1
private native synchronized String execute(Object oSync);

进入函数资源调用时:

1
env->MonitorEnter(syncObj);

释放时:

1
env->MonitorExit(syncObj);

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

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

多线程注意:

1
2
3
4
5
if (0 == gVm->AttachCurrentThread(&env, NULL))
{
gVm->DetachCurrentThread();
……
}

Comments