在前面文章中简单介绍了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数据类型
从上表中可以看出,Java的数据类型和C++的基本数据类型有一个映射关系,我们在使用JNI的时候可以直接使用Natvie Type来操作Native层的数据,这样就不用记忆复杂的映射关系了,从变量的名字上我们可以看到在Java的基本数据类型前面加一个字母‘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{ @Override protected 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); } @Override public 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 __cplusplus extern "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); //获得实例域Id jfieldID 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); }