1.通过JNI,java能够调用 C/C++函数,也能在C/C++ 里面调用 java 方法
The jsize
integer type is used to describe cardinal indices and sizes:
typedef jint jsize;
//-----------------------------------------------------------------------------------------
java端:
int sumResult = sum(10, 21);
String sResult = sumStr("Dai", "Wuhanshi");
Log.e("AAAA",""+sumResult);
Log.e("AAAA",sResult);
// 求和
public native int sum(int a,int b);
// 字符串连接
public native String sumStr(String strA,String strB);
native端:
/*
* Class: com_example_mystore_MainActivity
* Method: sum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_mystore_MainActivity_sum(
JNIEnv * pJNIEnv, jobject pThis, jint a, jint b) {
return a + b;
}
/*
* Class: com_example_mystore_MainActivity
* Method: sumStr
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_mystore_MainActivity_sumStr(
JNIEnv * pJNIEnv, jobject pThis, jstring a, jstring b) {
const char* aString = (*pJNIEnv)->GetStringUTFChars(pJNIEnv, a, 0);
const char* bString = (*pJNIEnv)->GetStringUTFChars(pJNIEnv, b, 0);
char* buf[1024];
strcpy(buf, aString);
strcat(buf, bString);
(*pJNIEnv)->ReleaseStringUTFChars(pJNIEnv, a, aString);
(*pJNIEnv)->ReleaseStringUTFChars(pJNIEnv, b, bString);
return (*pJNIEnv)->NewStringUTF(pJNIEnv, buf);
}
介绍了java端将String类型和int 类型作为参数传递到native端,
native端是如何进行处理的。
由于java程序中传过去的String对象在本地方法中对应的是jstring类型,jstring类型和c中的char*不同,所以如果你直接当做 char*使用的话,就会出错。因此在使用之前需要将jstring转换成为c/c++中的char*,这里使用JNIEnv的方法转换。
const char* aString = (*pJNIEnv)->GetStringUTFChars(pJNIEnv, a, 0);
这里其实只是得到a的一个copy.所以用完后,还需要通过 ReleaseStringUTFChars这方法进行释放
GetStringUTFChars 和 ReleaseStringUTFChars 这两方法需要成对出现.
//---------------------- 在native里面进行 抛异常
主要代码为:
package com.example.mystore;
public class MyException extends Exception {
private String message;
public MyException(String name) {
super(name);
message = name;
}
public String getMessageString() {
return message;
}
}
package com.example.mystore;
public class Dog {
private String name;
private int age;
public Dog(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public native Dog getDog() throws MyException;
Dog newDog = null;
try {
newDog = getDog();
Log.e("AAAA", newDog.getName() + ":" + newDog.getAge());
} catch (MyException e) {
Log.e("AAAA", e.getMessageString());
}
现在再看native端的代码:
/*
* Class: com_example_mystore_MainActivity
* Method: getDog
* Signature: ()Lcom/example/mystore/Dog;
*/
JNIEXPORT jobject JNICALL Java_com_example_mystore_MainActivity_getDog(
JNIEnv * pJNIEnv, jobject pThis) {
if (globalObject == NULL) {
throwMyException(pJNIEnv);
return NULL;
}
CCLog(TAG,"到这里了");
return globalObject;
}
void throwMyException(JNIEnv * pJNIEnv) {
jclass lClass = (*pJNIEnv)->FindClass(pJNIEnv,
"com/example/mystore/MyException");
if (lClass != NULL) {
(*pJNIEnv)->ThrowNew(pJNIEnv, lClass, "没有发现aa啊!!!");
}
(*pJNIEnv)->DeleteLocalRef(pJNIEnv, lClass);
}
在 native端,其实是通过 throwMyException 这个方法,
然后,找到异常类,通过如下语句
(*pJNIEnv)->ThrowNew(pJNIEnv, lClass, "没有发现aa啊!!!");
抛出异常.
注意,在 throwMyException这方法里面,JNI里面的 Local引用需要手动删除.
//-----------------------------------------------------------------------------------
传递基本类型的数组
JNIEXPORT void JNICALL Java_com_example_mystore_MainActivity_saveIntArr(
JNIEnv * pJNIEnv, jobject pThis, jintArray jay) {
// 先得到数组的长度
jsize lLength = (*pJNIEnv)->GetArrayLength(pJNIEnv, jay);
// 分配内存
int* lArray = (int*) malloc(sizeof(int) * lLength);
//将传递过来的数据放入
(*pJNIEnv)->GetIntArrayRegion(pJNIEnv, jay, 0, lLength, lArray);
//需要检查是否出现异常
if ((*pJNIEnv)->ExceptionCheck(pJNIEnv)) {
free(lArray);
return;
}
//将传递过来的int数组打印出来
jint i = 0;
for (i = 0; i < lLength; ++i) {
//(*pJNIEnv)->GetIntArrayElements(pJNIEnv,jay,);
CCLog("AAAA", "%d \n", lArray[i]);
}
free(lArray);
}
从native端传递基本类型数组到java端
JNIEXPORT jintArray JNICALL Java_com_example_mystore_MainActivity_getIntArray(
JNIEnv * pJNIEnv, jobject pThis) {
//我想返回 2,4,6,8组成的数组
// 先创建
jintArray lJavaArray = (*pJNIEnv)->NewIntArray(pJNIEnv, 4);
if (lJavaArray == NULL) {
return NULL;
}
int target[] = { 2, 4, 6, 8 };
(*pJNIEnv)->SetIntArrayRegion(pJNIEnv, lJavaArray, 0, 4, target);
return lJavaArray;
}
//----------------------
从java端传递对象数组到native端
JNIEXPORT void JNICALL Java_com_example_mystore_MainActivity_saveDogArr(
JNIEnv * pJNIEnv, jobject pThis, jobjectArray joa) {
//先得到个数
jsize lLength = (*pJNIEnv)->GetArrayLength(pJNIEnv, joa);
//分配内存
jobject* lArray = (jobjectArray*) malloc(lLength * sizeof(jobject));
//将传入的数据放入
int i = 0;
for (i = 0; i < lLength; ++i) {
jobject obj = (*pJNIEnv)->GetObjectArrayElement(pJNIEnv, joa, i);
lArray[i] = (*pJNIEnv)->NewGlobalRef(pJNIEnv, obj);
(*pJNIEnv)->DeleteLocalRef(pJNIEnv, obj);
}
globalObjectArray = lArray;
gLength = lLength;
}
从native端传递对象数组到java端
JNIEXPORT jobjectArray JNICALL Java_com_example_mystore_MainActivity_getDogArr(
JNIEnv * pJNIEnv, jobject pThis) {
// 先找到class
jclass dogClass = (*pJNIEnv)->FindClass(pJNIEnv, "com/example/mystore/Dog");
//检查是否找到dogclass
if (dogClass == NULL) {
CCLog("AAAA", "没有找到dogClass");
return NULL;
}
jobjectArray joa = (*pJNIEnv)->NewObjectArray(pJNIEnv, gLength, dogClass,
NULL);
(*pJNIEnv)->DeleteLocalRef(pJNIEnv, dogClass);
int i = 0;
for (i = 0; i < gLength; ++i) {
(*pJNIEnv)->SetObjectArrayElement(pJNIEnv, joa, i,
globalObjectArray[i]);
if ((*pJNIEnv)->ExceptionCheck(pJNIEnv)) {
CCLog("AAAA", "[SetObjectArrayElement] 里面出现错误!!!");
return NULL;
}
}
return joa;
}
总结一下:
1.从native端传递到java端的时候,一般都是通过(*pJNIEnv)->NewXXXXX(pJNIEnv,xxx);生成,然后再返回.
方法里面 类似
jclass dogClass = (*pJNIEnv)->FindClass(pJNIEnv, "com/example/mystore/Dog");
或者
jobject obj = (*pJNIEnv)->GetObjectArrayElement(pJNIEnv, joa, i);
这样的调用,使用完毕后,需要将这样的局部使用
引用进行删除.(*pJNIEnv)->DeleteLocalRef(pJNIEnv, xxx);
2.native端如果需要保存java端传递过来的对象或者数据,native端需要自己管理好内存.