在寫android程式的時候會用到jni,接下來的代碼講訴C實現,環境配置請看我其他的部落格,不多說,直接上代碼,代碼上幾乎每一句都會解釋,絕對易懂
#include "com_ndk_test_JniClient.h"#include <stdlib.h>//#include<jni.h>#include <stdio.h>#define ARRAY_LENGTH 5//宏定義#ifdef __cplusplusextern "C"{#endif/* * Class: com_ndk_test_JniClient * Method: AddStr * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_ndk_test_JniClient_AddStr(JNIEnv *env,jclass arg, jstring a, jstring b) {//JNIEnv也是在jni.h中定義的,代表JNI調用的上下文,//GetStringUTFChars()、ReleaseStringUTFChars()和NewStringUTF()均是JNIEnv的函數。//jstring str = (*env)->NewStringUTF(env, "HelloWorld from JNI !");//從JNI調用上下文中擷取UTF編碼的輸入字元,將其放在指標str所指向 的一段記憶體中const char* str = (*env)->GetStringUTFChars(env, a, 0); //這是c的寫法,接下來沒有注釋的都是有c編寫//const char* s1 = env->GetStringUTFChars(a, 0);//這是c++的寫法,以下的方法都是這種形式char cap[128]; //定義char數組strcpy(cap, str); //複製字串到cap(*env)->ReleaseStringUTFChars(env, a, str); //釋放這段記憶體,個人認為這個像c++虛函數int i = 0;for (i = 0; i < strlen(cap); i++)*(cap + i) = (char) toupper(*(cap + i)); //將經過大寫轉換的字串予以返回return (*env)->NewStringUTF(env, cap); //C語言的字串指標 轉換為JNI的jstring類型//return (*env)->NewStringUTF(env, strupr(cap));//return str;}/* * Class: com_ndk_test_JniClient * Method: AddInt * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_ndk_test_JniClient_AddInt(JNIEnv *env,jclass arg, jint a, jint b) {return a + b;};//TODOJNIEXPORT jint JNICALL Java_com_ndk_test_JniClient_intArrayMethord(JNIEnv * env,jclass clazz, jintArray array) {//return 200;int i, sum = 0;jsize len = (*env)->GetArrayLength(env, array);jint *body = (*env)->GetIntArrayElements(env, array, 0);for (i = 0; i < len; i++) {sum += body[i];}(*env)->ReleaseIntArrayElements(env, array, body, 0);return sum;}JNIEXPORT jboolean JNICALL Java_com_ndk_test_JniClient_booleanMethord(JNIEnv *env, jclass clazz, jboolean b) {return b;}/** * * 以下代碼需要在java程式中聲明,標頭檔中也沒有改寫 * */JNIEXPORT jintArray JNICALL Java_com_ndk_test_JniClient_intMethord(JNIEnv *env,jclass clazz) {int i = 1; //jint是在JNI框 架內特有的整數類型jintArray array; //定義數組對象array = (*env)->NewIntArray(env, 10); //開闢出一個長度為10 的jint數組for (; i <= 10; i++) //依次向該數組中放入元素1-10(*env)->SetIntArrayRegion(env, array, i - 1, 1, &i);//示範GetArrayLength() 和GetIntArrayElements()這兩個函數的使用方法/* 擷取數組對象的元素個數 */int len = (*env)->GetArrayLength(env, array);/* 擷取數組中的所有元素 */jint* elems = (*env)->GetIntArrayElements(env, array, 0);for (i = 0; i < len; i++)printf("ELEMENT %d IS %d/n", i, elems[i]);return array;}/** * 所有的本地方法的第一個參數都是指向JNIEnv結構的。 * 這個結構是用來調用JNI函數的。第二個參數jclass的意義, * 要看方法是不是靜態(static)或者執行個體(Instance)的。 * 前者,jclass代表一個類對象的引用,而後者是被調用的方法所屬對象的引用。 * 深化:雖然仍然是傳遞數組,但是數組的基類換成了字串這樣一種對象資料類型。 * Java程式將向C程式傳入一個包含中文字元的字串, * C程式並沒有處理這個字串,而是開闢出一個新的字串數組返回給Java程式,其中還包含兩個漢字字串。 * java寫法----->: public native String[] stringMethod(String text); public static void main(String[] args) throws java.io.UnsupportedEncodingException { System.loadLibrary("Sample3"); Sample3 sample = new Sample3(); String[] texts = sample.stringMethod("java編程思想"); for(int i=0;i<texts.length;i++) { texts[i]=new String(texts[i].getBytes("ISO8859-1"),"GBK"); System.out.print( texts[i] ); } System.out.println(); } * */JNIEXPORT jobjectArray JNICALL Java_com_ndk_test_JniClient_stringMethord(JNIEnv *env, jclass obj, jstring string) {//通過FindClass()函數在JNI上下文中擷取到java.lang.String的類型 (Class),並將其賦予jclass變數jclass objClass = (*env)->FindClass(env, "java/lang/String");//JNI架構並 沒有定義專門的字串數組,//而是使用jobjectArray——對象數組,//對象數組的基類是jclass,jclass是JNI架構內特有的類型,//相當 於Java語言中的Class類型//定義了一個長度為5的對象數組textsjobjectArray texts = (*env)->NewObjectArray(env, (jsize) ARRAY_LENGTH,objClass, 0);jstring jstr;char* sa[] = { "Hello,", "world!", "JNI", "很", "好玩" };int i = 0;//迴圈放入預先定義好的sa數組中的字串,//當然前置條件是使用NewStringUTF()函數將C語言的字串轉換為jstring類型for (; i < ARRAY_LENGTH; i++) {jstr = (*env)->NewStringUTF(env, sa[i]);(*env)->SetObjectArrayElement(env, texts, i, jstr); //必須放入jstring}//中文字元則是用支援GBK的IME輸入的,而Java程式採用 ISO8859_1字元集存放JNI調用的返回字元return texts;}/** * 示範的是C程式向Java程式傳遞對象數組, * 而且對象數組中存放的不再是字串, * 而是一個在Java中自訂的、含有一個topic屬性的MailInfo物件類型 *MailInfo對象定義如下:-> public class MailInfo { public String topic; public String getTopic() { return this.topic; } public void setTopic(String topic) { this.topic=topic; } } Java程式的原始碼如下:-> public class Sample4 { public native MailInfo[] objectMethod(String text); public static void main(String[] args) { System.loadLibrary("Sample4"); Sample4 sample = new Sample4(); MailInfo[] mails = sample.objectMethod("Thinking In Java"); for(int i=0;i<mails.length;i++) System.out.println(mails[i].topic); } } * */JNIEXPORT jboolean JNICALL Java_com_ndk_test_JniClient_objectMethod(JNIEnv *env,jobject obj, jstring string) {//這次通過FindClass()函數在JNI上下文中擷取的是java.lang.Object的類型(Class),//並將 其作為基類開闢出一個長度為5的對象數組( #define ARRAY_LENGTH 5),準備用來存放MailInfo對象。class objClass = (*env)->FindClass(env, "java/lang/Object");jobjectArray mails = (*env)->NewObjectArray(env, (jsize) ARRAY_LENGTH,objClass, 0);jclass objectClass = (*env)->FindClass(env, "MailInfo");//建立一個jfieldID類型的變數,在JNI中,操作對 象屬性都是通過jfieldID進行的.//首先尋找得到MailInfo的類型(Class),//然後基於這個jclass進一步擷取其名為 topic的屬性,並將其賦予jfieldID變數。jfieldID topicFieldId = (*env)->GetFieldID(env, objectClass, "topic","Ljava/lang/String;");int i = 0;//迴圈向對象數組中放入jobject對象。 SetObjectField()函數屬於首次使用,//該函數的作用是向jobject的屬性賦值,而值的內容正是Java程式傳入的jstring變數 值。//請注意在向對象屬性賦值和向對象數組中放入對象的過程中,//我們使用了在函數頭部分定義的jobject類型的環境參數obj作為中介。//至此,JNI框 架固有的兩個環境入參env和obj,我們都有涉及。for (; i < ARRAY_LENGTH; i++) {(*env)->SetObjectField(env, obj, topicFieldId, string);(*env)->SetObjectArrayElement(env, mails, i, obj);}return mails;}#ifdef __cplusplus}#endif
package com.ndk.test;public class JniClient {static {System.loadLibrary("TestNdk");}private JniClient() {}private static JniClient jniClient = new JniClient();public static JniClient getInstance() {return jniClient;}public native String AddStr(String strA, String strB);public native int AddInt(int a, int b);// ==============public native int intArrayMethord(int[] intArray);public native boolean booleanMethord(boolean b);}