閱讀本文前,請先閱讀java
★表明難度等級android
以前咱們實現了從C代碼裏返回了一個字符串,代碼以下:數組
java代碼,定義native函數bash
public class Jni {
static {
System.loadLibrary("best");
}
public native String sayHello();
}
複製代碼
javah 生成jni樣式的標準頭文件ide
這裏略去了生成
jni_study_com_jnibsetpractice_Jni.h
的具體,下面會再次提到函數
c代碼,實現java裏的native方法工具
# include "jni_study_com_jnibsetpractice_Jni.h"
JNIEXPORT jstring JNICALL Java_jni_study_com_jnibsetpractice_Jni_sayHello
(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, "Hello from C");
}
複製代碼
java裏調用native方法post
bt_1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String hello = jni.sayHello();
Toast.makeText(MainActivity.this,hello,Toast.LENGTH_LONG).show();
}
});
複製代碼
java代碼,定義native函數ui
public class Jni {
static {
System.loadLibrary("best");
}
public native int add(int x,int y);
}
複製代碼
javah 生成jni樣式的標準頭文件this
切換到src/main/java目錄下執行
javah -d ../jni jni.study.com.jnibsetpractice.Jni
複製代碼
注意:javah 後半段跟的是 這個native方法所在的類的全路徑名稱
打開這個文件,發現生成了java裏的這個native方法的jni方法簽名
JNIEXPORT jint JNICALL Java_jni_study_com_jnibsetpractice_Jni_add
(JNIEnv *, jobject, jint, jint);
複製代碼
public native int add(int x,int y);
複製代碼
對比一下:
int
對應jint
add
對應Java_jni_study_com_jnibsetpractice_Jni_add
(int ,int )
對應(JNIEnv *, jobject, jint, jint)
這裏說明一下
參數JNIEnv * :jni的環境,經過它來調用內置的不少jni方法
參數jobject:表明在java裏調用這個native方法的實例對象(若是是靜態方法表明的是類) 參數jint, jint:對應 int x,int y
JNIEnv是什麼在JNI相關概念的理解文章裏有詳細解釋
jint和int關係在JNI相關概念的理解文章裏也有詳細解釋
c代碼,實現java裏的native方法
# include "jni_study_com_jnibsetpractice_Jni.h"
JNIEXPORT jint JNICALL Java_jni_study_com_jnibsetpractice_Jni_add
(JNIEnv * env, jobject instance, jint x, jint y){
return x+y;
}
複製代碼
Java調用native方法
bt_2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int add = jni.add(1, 2);
Toast.makeText(MainActivity.this, "1+2=" + add, Toast.LENGTH_LONG).show();
}
});
複製代碼
ok,完成了,是否是很簡單,若是java傳遞string給C也是這麼簡單嗎,記得嗎java裏的string與c裏的string但是不同喲
public class Jni {
static {
System.loadLibrary("best");
}
public native String transe_string(String str);
}
複製代碼
生成文件的方法略,直接分析這個文件
JNIEXPORT jstring JNICALL Java_jni_study_com_jnibsetpractice_Jni_transe_1string
(JNIEnv *, jobject, jstring);
複製代碼
public native String transe_string(String str);
複製代碼
對比一下: jstring
對應String
看看jstring是什麼
java傳給c一個string,javah生成了方法名後, 發現傳遞來的是一個jstring(由於在c裏,是沒有string的), jstring實際上是void*(任意類型), 咱們須要調用一個方法,把jstring轉爲C語言的char*類型,先看下這個工具方法:
#include <stdlib.h>
/**
* 把一個jstring轉換成一個c語言的char* 類型.
*/
char* _JString2CStr(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, "java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if(alen > 0) {
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn, ba, alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba,0);
return rtn;
}
複製代碼
實現native方法
JNIEXPORT jstring JNICALL Java_jni_study_com_jnibsetpractice_Jni_transe_1string
(JNIEnv *env, jobject instance, jstring jstr) {
//把一個jstring轉換成一個c語言的char* 類型
char *cStr = _JString2CStr(env, jstr);
//c語言拼接字符串
char *cNewStr = strcat(cStr, "簡單加密一下哈哈哈!!!");
// 把c語言裏的char* 字符串轉成java認識的字符串
return (*env)->NewStringUTF(env, cNewStr);
}
複製代碼
bt_3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str = jni.transe_string("abc");
Toast.makeText(MainActivity.this, "abc ====c轉換=====> " + str, Toast.LENGTH_LONG).show();
}
});
複製代碼
public class Jni {
static {
System.loadLibrary("best");
}
public native int[] transeIntArray(int[] intArray);
}
複製代碼
生成jni頭文件的方法 略
JNIEXPORT jintArray JNICALL Java_jni_study_com_jnibsetpractice_Jni_transeIntArray
(JNIEnv *, jobject, jintArray);
複製代碼
public native int[] transeIntArray(int[] intArray);
複製代碼
jintArray
對應int[]
JNIEXPORT jintArray JNICALL Java_jni_study_com_jnibsetpractice_Jni_transeIntArray
(JNIEnv *env, jobject instance, jintArray jArray) {
// 獲得從java傳遞來的int[]的長度
jsize length = (*env)->GetArrayLength(env, jArray);
// 獲得數組指針
int *arrayPointer = (*env)->GetIntArrayElements(env, jArray, NULL);
// 開始遍歷數組,把每一個元素加100
int i;
for (i = 0; i < length; i++) {
*(arrayPointer + i) += 100;
}
// ★★★★將arrayPointer這個int *中值複製到jArray數組中,別忘了這一步驟★★★
(*env)->SetIntArrayRegion(env,jArray, 0, length, arrayPointer);
// 返回數組
return jArray;
}
複製代碼
bt_4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int[] intArray = new int[]{1, 2, 3};
int[] intArrayTranse = jni.transeIntArray(intArray);
for (int i = 0; i < intArray.length; i++) {
//發如今這裏遍歷舊的數組,打印出來也是加過100後的數字,101,102,103
// 由於C是經過指針操做內存地址,改變了intArray的內存地址的值,
// 因此C裏面不返回int[]也是能夠實現目的的
Log.e("abc",intArray[i]+"old");
}
for (int i = 0; i < intArrayTranse.length; i++) {
Log.e("abc",intArrayTranse[i]+"new");
}//這裏打印的是101,102,103
}
});
複製代碼
log以下
前面講的都是java調用C的方法,有時候咱們需C裏調用Java的方法,
例如:咱們有一個操做圖片的方法是C寫的,在C操做圖片是,須要讓android彈出一個進度條,展現圖片操做的進度,這時候,就須要C代碼裏調用java代碼,來改變UI了
待續。。。。。。。。。。。。。。。。