標籤:android ndk jni
在前面文章中簡單介紹了JNI,這一篇文章來簡單看一下jni.h中定義的一些常用方法,來實現通過C++調用Android中的Java代碼。
轉載請說明出處:http://blog.csdn.net/dawanganban
一、兩個參數的介紹
在前面的代碼中我們會遇到兩個參數,下面對這兩個參數做一解釋
1、JNIEnv是指向可用JNI函數表的介面指標,C代碼中JNIEnv是指向JNINativeInterface結構的指標,在C語言中JNIEnv必須作為第一個參數傳入每一個JNI函數的調用者,如:
(*env)->NewStringUTF(env, "helloworld");
在C++中,JNIEnv是C++類的執行個體,JNI函數以成員函數形式存在,所以在JNI環境中,無序傳入該參數,如:
env->NetStringUTF("helloworld");2、jobject是一個指向java對象的引用,如果本地方法是一個靜態方法,則是指向類位元組碼檔案的class對象。
二、JNI資料類型
1、基本類型映射
從上表中可以看出,Java的資料類型和C++的基礎資料型別 (Elementary Data Type)有一個映射關係,我們在使用JNI的時候可以直接使用Natvie Type來操作Native層的資料,這樣就不用記憶複雜的映射關係了,從變數的名字上我們可以看到在Java的基礎資料型別 (Elementary Data Type)前面加一個字母‘j‘就是對應的C++的Native類型。
2、參考型別映射
與基本類型不同的是,參考型別對原生的方法是不透明的(不能直接使用和修改),JNI提供了與這些參考型別密切相關的一組API,這些API通過JNIEnv介面指標提供給原生函數。
我們在jni.h中可以看到上面類型的定義:
class _jobject {};class _jclass : public _jobject {};class _jthrowable : public _jobject {};class _jstring : public _jobject {};class _jarray : public _jobject {};class _jbooleanArray : public _jarray {};class _jbyteArray : public _jarray {};class _jcharArray : public _jarray {};class _jshortArray : public _jarray {};class _jintArray : public _jarray {};class _jlongArray : public _jarray {};class _jfloatArray : public _jarray {};class _jdoubleArray : public _jarray {};class _jobjectArray : public _jarray {};typedef _jobject *jobject;typedef _jclass *jclass;typedef _jthrowable *jthrowable;typedef _jstring *jstring;typedef _jarray *jarray;typedef _jbooleanArray *jbooleanArray;typedef _jbyteArray *jbyteArray;typedef _jcharArray *jcharArray;typedef _jshortArray *jshortArray;typedef _jintArray *jintArray;typedef _jlongArray *jlongArray;typedef _jfloatArray *jfloatArray;typedef _jdoubleArray *jdoubleArray;typedef _jobjectArray *jobjectArray;這些類的設計和Java一樣,都繼承自一個名為_jobject的父類。
三、對參考型別操作的例子
package com.example.test;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Toast;import com.example.myfirstjniproj.R;/** * 陽光小強 http://blog.csdn.net/dawanganban * @author lixiaoqiang * */public class MainActivity extends Activity implements OnClickListener{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.jni_jstring_button).setOnClickListener(this);findViewById(R.id.jni_javaArray_button).setOnClickListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.jni_jstring_button:showToast(jniStringTest("input string"));break;case R.id.jni_javaArray_button:int[] array = jniArrayTest();showToast("arr[1]=" + array[1] + " : arr[2]=" + array[2]);break;default:break;}}private void showToast(String content){Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();}public native String jniStringTest(String str);public native int[] jniArrayTest();static{System.loadLibrary("jnitest");}}通過javah產生的標頭檔
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_test_MainActivity */#ifndef _Included_com_example_test_MainActivity#define _Included_com_example_test_MainActivity#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_test_MainActivity * Method: jniStringTest * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_jniStringTest (JNIEnv *, jobject, jstring);/* * Class: com_example_test_MainActivity * Method: jniArrayTest * Signature: ()[I */JNIEXPORT jintArray JNICALL Java_com_example_test_MainActivity_jniArrayTest (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endifc++實現
#include "com_example_test_MainActivity.h"#include <stdlib.h>using namespace std;JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_jniStringTest (JNIEnv * env, jobject obj, jstring str){//將java字串轉成c++字串jboolean isCopy;const char* cstr = env->GetStringUTFChars(str, &isCopy);//釋放原生字串env->ReleaseStringUTFChars(str, cstr);//建立字串jstring jstr = env->NewStringUTF("hello world");;return jstr;}JNIEXPORT jintArray JNICALL Java_com_example_test_MainActivity_jniArrayTest (JNIEnv * env, jobject obj){//建立一個10個元素的數組jintArray intarray = env->NewIntArray(10);if(0 != intarray){jint nativeArray[10];//擷取原生的數組env->GetIntArrayRegion(intarray, 0, 10, nativeArray);nativeArray[1] = 10;nativeArray[2] = 20;//設定改變env->SetIntArrayRegion(intarray, 0, 10, nativeArray);}return intarray;}四、訪問域和擷取ID
Java有兩個域:執行個體域和靜態域,每個執行個體都有自己的執行個體域副本,而一個類的所有執行個體共用一個靜態域。
JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_getInstanceField (JNIEnv * env, jobject obj){//通過對象獲得類jclass clazz;clazz = env->GetObjectClass(obj);//獲得執行個體域IdjfieldID instanceFieldId;instanceFieldId = env->GetFieldID(clazz, "instanceField", "Ljava/lang/String");//獲得執行個體域jobject instanceField;instanceField = env->GetObjectField(obj, instanceFieldId);jstring jstr = env->NewStringUTF("擷取成功");return jstr;}JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_getStaticField (JNIEnv * env, jobject obj){jclass clazz;clazz = env->GetObjectClass(obj);jfieldID staticFieldId;staticFieldId = env->GetStaticFieldID(clazz, "staticField", "Ljava/lang/String");jobject staticField;staticField = env->GetStaticObjectField(clazz, staticFieldId);jstring jstr = env->NewStringUTF("擷取成功");return jstr;}在上面代碼中我們看到了“Ljava/lang/String"字串,這個是擷取ID的類型簽名,Java的類型簽名映射表如下:
五、調用Java中的方法
與上面的域一樣,Java中也有兩類方法,執行個體方法和靜態方法,JNI提供了兩類方法的函數
public native void getInstanceMethod();public native void getStaticMethod();public String instanceMethod(){return "instanceMethod";}public static String staticMethod(){return "staticMethod";}
JNIEXPORT void JNICALL Java_com_example_test_MainActivity_getInstanceMethod (JNIEnv * env, jobject obj){jclass clazz;clazz = env->GetObjectClass(obj);jmethodID instanceMethodId;instanceMethodId = env->GetMethodID(clazz, "instanceMethod", "()Ljava/lang/String");jstring instanceMethodResult;instanceMethodResult = env->CallStringMethod(obj, instanceMethodId);}JNIEXPORT void JNICALL Java_com_example_test_MainActivity_getStaticMethod (JNIEnv * env, jobject obj){jclass clazz;clazz = env->GetObjectClass(obj);jmethodID staticMethodId;staticMethodId = env->GetStaticMethodID(clazz, "staticMethod", "()Ljava/lang/String");jstring staticMethodResult;staticMethodResult = env->CallStaticStringMethod(clazz, staticMethodId);}
深入理解Android(4)——理解Android中的JNI(下)