在前面文章中简单介绍了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++的基本数据类型有一个映射关系,我们在使用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;
-
-
-
-
-
-
- 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生成的头文件
-
- #include <jni.h>
-
-
- #ifndef _Included_com_example_test_MainActivity
- #define _Included_com_example_test_MainActivity
- #ifdef __cplusplus
- extern "C" {
- #endif
-
-
-
-
-
- JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_jniStringTest
- (JNIEnv *, jobject, jstring);
-
-
-
-
-
-
- JNIEXPORT jintArray JNICALL Java_com_example_test_MainActivity_jniArrayTest
- (JNIEnv *, jobject);
-
- #ifdef __cplusplus
- }
- #endif
- #endif
c++实现
- #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){
-
- 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){
-
- 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);
-
- 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);
- }