深入理解Android(4)——理解Android中的JNI(下)

在前面文章中简单介绍了JNI,这一篇文章来简单看一下jni.h中定义的一些常用方法,来实现通过C++调用Android中的Java代码。

转载请说明出处:http://blog.csdn.net/dawanganban

一、两个参数的介绍

在前面的代码中我们会遇到两个参数,下面对这两个参数做一解释

1、JNIEnv是指向可用JNI函数表的接口指针,C代码中JNIEnv是指向JNINativeInterface结构的指针,在C语言中JNIEnv必须作为第一个参数传入每一个JNI函数的调用者,如:

  1. (*env)->NewStringUTF(env, "helloworld");  
在C++中,JNIEnv是C++类的实例,JNI函数以成员函数形式存在,所以在JNI环境中,无序传入该参数,如:

  1. 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中可以看到上面类型的定义:

  1. class _jobject {};  
  2. class _jclass : public _jobject {};  
  3. class _jthrowable : public _jobject {};  
  4. class _jstring : public _jobject {};  
  5. class _jarray : public _jobject {};  
  6. class _jbooleanArray : public _jarray {};  
  7. class _jbyteArray : public _jarray {};  
  8. class _jcharArray : public _jarray {};  
  9. class _jshortArray : public _jarray {};  
  10. class _jintArray : public _jarray {};  
  11. class _jlongArray : public _jarray {};  
  12. class _jfloatArray : public _jarray {};  
  13. class _jdoubleArray : public _jarray {};  
  14. class _jobjectArray : public _jarray {};  
  15.   
  16. typedef _jobject *jobject;  
  17. typedef _jclass *jclass;  
  18. typedef _jthrowable *jthrowable;  
  19. typedef _jstring *jstring;  
  20. typedef _jarray *jarray;  
  21. typedef _jbooleanArray *jbooleanArray;  
  22. typedef _jbyteArray *jbyteArray;  
  23. typedef _jcharArray *jcharArray;  
  24. typedef _jshortArray *jshortArray;  
  25. typedef _jintArray *jintArray;  
  26. typedef _jlongArray *jlongArray;  
  27. typedef _jfloatArray *jfloatArray;  
  28. typedef _jdoubleArray *jdoubleArray;  
  29. typedef _jobjectArray *jobjectArray;  
这些类的设计和Java一样,都继承自一个名为_jobject的父类。

三、对引用类型操作的例子

  1. package com.example.test;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.View;  
  6. import android.view.View.OnClickListener;  
  7. import android.widget.Toast;  
  8.   
  9. import com.example.myfirstjniproj.R;  
  10.   
  11. /** 
  12.  * 阳光小强 http://blog.csdn.net/dawanganban 
  13.  * @author lixiaoqiang 
  14.  * 
  15.  */  
  16. public class MainActivity extends Activity implements OnClickListener{  
  17.   
  18.     @Override  
  19.     protected void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.activity_main);  
  22.           
  23.         findViewById(R.id.jni_jstring_button).setOnClickListener(this);  
  24.         findViewById(R.id.jni_javaArray_button).setOnClickListener(this);  
  25.     }  
  26.   
  27.     @Override  
  28.     public void onClick(View view) {  
  29.         switch (view.getId()) {  
  30.         case R.id.jni_jstring_button:  
  31.             showToast(jniStringTest("input string"));  
  32.             break;  
  33.         case R.id.jni_javaArray_button:  
  34.             int[] array = jniArrayTest();  
  35.             showToast("arr[1]=" + array[1] + " : arr[2]=" + array[2]);  
  36.             break;  
  37.         default:  
  38.             break;  
  39.         }  
  40.     }  
  41.       
  42.     private void showToast(String content){  
  43.         Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();  
  44.     }  
  45.       
  46.     public native String jniStringTest(String str);  
  47.       
  48.     public native int[] jniArrayTest();  
  49.       
  50.       
  51.     static{  
  52.         System.loadLibrary("jnitest");  
  53.     }  
  54. }  
通过javah生成的头文件

  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_example_test_MainActivity */  
  4.   
  5. #ifndef _Included_com_example_test_MainActivity  
  6. #define _Included_com_example_test_MainActivity  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_example_test_MainActivity 
  12.  * Method:    jniStringTest 
  13.  * Signature: (Ljava/lang/String;)Ljava/lang/String; 
  14.  */  
  15. JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_jniStringTest  
  16.   (JNIEnv *, jobject, jstring);  
  17.   
  18. /* 
  19.  * Class:     com_example_test_MainActivity 
  20.  * Method:    jniArrayTest 
  21.  * Signature: ()[I 
  22.  */  
  23. JNIEXPORT jintArray JNICALL Java_com_example_test_MainActivity_jniArrayTest  
  24.   (JNIEnv *, jobject);  
  25.   
  26. #ifdef __cplusplus  
  27. }  
  28. #endif  
  29. #endif  
c++实现

  1. #include "com_example_test_MainActivity.h"  
  2. #include <stdlib.h>  
  3. using namespace std;  
  4.   
  5. JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_jniStringTest  
  6.   (JNIEnv * env, jobject obj, jstring str){  
  7.     //将java字符串转成c++字符串  
  8.     jboolean isCopy;  
  9.     const char* cstr = env->GetStringUTFChars(str, &isCopy);  
  10.     //释放原生字符串  
  11.     env->ReleaseStringUTFChars(str, cstr);  
  12.     //创建字符串  
  13.     jstring jstr = env->NewStringUTF("hello world");;  
  14.   
  15.     return jstr;  
  16. }  
  17.   
  18. JNIEXPORT jintArray JNICALL Java_com_example_test_MainActivity_jniArrayTest  
  19.   (JNIEnv * env, jobject obj){  
  20.     //创建一个10个元素的数组  
  21.     jintArray intarray = env->NewIntArray(10);  
  22.     if(0 != intarray){  
  23.         jint nativeArray[10];  
  24.         //获取原生的数组  
  25.         env->GetIntArrayRegion(intarray, 0, 10, nativeArray);  
  26.         nativeArray[1] = 10;  
  27.         nativeArray[2] = 20;  
  28.         //设置改变  
  29.         env->SetIntArrayRegion(intarray, 0, 10, nativeArray);  
  30.     }  
  31.     return intarray;  
  32. }  
四、访问域和获取ID

Java有两个域:实例域和静态域,每个实例都有自己的实例域副本,而一个类的所有实例共享一个静态域。

  1. JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_getInstanceField  
  2.   (JNIEnv * env, jobject obj){  
  3.     //通过对象获得类  
  4.     jclass clazz;  
  5.     clazz = env->GetObjectClass(obj);  
  6.     //获得实例域Id  
  7.     jfieldID instanceFieldId;  
  8.     instanceFieldId = env->GetFieldID(clazz, "instanceField""Ljava/lang/String");  
  9.     //获得实例域  
  10.     jobject instanceField;  
  11.     instanceField = env->GetObjectField(obj, instanceFieldId);  
  12.     jstring jstr = env->NewStringUTF("获取成功");  
  13.     return jstr;  
  14. }  
  15.   
  16.   
  17. JNIEXPORT jstring JNICALL Java_com_example_test_MainActivity_getStaticField  
  18.   (JNIEnv * env, jobject obj){  
  19.     jclass clazz;  
  20.     clazz = env->GetObjectClass(obj);  
  21.     jfieldID staticFieldId;  
  22.     staticFieldId = env->GetStaticFieldID(clazz, "staticField""Ljava/lang/String");  
  23.     jobject staticField;  
  24.     staticField = env->GetStaticObjectField(clazz, staticFieldId);  
  25.     jstring jstr = env->NewStringUTF("获取成功");  
  26.     return jstr;  
  27. }  
在上面代码中我们看到了“Ljava/lang/String"字符串,这个是获取ID的类型签名,Java的类型签名映射表如下:


五、调用Java中的方法

与上面的域一样,Java中也有两类方法,实例方法和静态方法,JNI提供了两类方法的函数

  1. public native void getInstanceMethod();  
  2.   
  3. public native void getStaticMethod();  
  4.   
  5. public String instanceMethod(){  
  6.     return "instanceMethod";  
  7. }  
  8.   
  9. public static String staticMethod(){  
  10.     return "staticMethod";  
  11. }  
  1. JNIEXPORT void JNICALL Java_com_example_test_MainActivity_getInstanceMethod  
  2.   (JNIEnv * env, jobject obj){  
  3.     jclass clazz;  
  4.     clazz = env->GetObjectClass(obj);  
  5.     jmethodID instanceMethodId;  
  6.     instanceMethodId = env->GetMethodID(clazz, "instanceMethod""()Ljava/lang/String");  
  7.     jstring instanceMethodResult;  
  8.     instanceMethodResult = env->CallStringMethod(obj, instanceMethodId);  
  9. }  
  10.   
  11. JNIEXPORT void JNICALL Java_com_example_test_MainActivity_getStaticMethod  
  12.   (JNIEnv * env, jobject obj){  
  13.     jclass clazz;  
  14.     clazz = env->GetObjectClass(obj);  
  15.     jmethodID staticMethodId;  
  16.     staticMethodId = env->GetStaticMethodID(clazz, "staticMethod""()Ljava/lang/String");  
  17.     jstring staticMethodResult;  
  18.     staticMethodResult = env->CallStaticStringMethod(clazz, staticMethodId);  
  19. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值