Android内核学习之二------JNI的使用

来源:互联网 发布:美工与设计师的区别 编辑:程序博客网 时间:2024/06/05 22:56

Android内核学习之二

-----JNI的使用

1.  学习前言

JNI即JAVA Native Interface,提供了若干API实现java与c/c++的通信。也可以说它提供了一种方法,我们只要采用这种方法遵循JNI的固定格式就很容易的实现java和c/c++的混编。JNI以前在做java web的时候用的比较少,仅仅算是接触过。但是在android里面就不同了,由于android的底层都是c/c++实现的,而上层的app又都是java实现的。所以在中间(一般是frameworks层)大量使用了JNI来实现java与c/c++的交互。

本来没想到要记录下这一块内容,但是后来发现JNI在里面用的实在是太多了。尤其是再看4.4.2的源码的时候,发现很多上层的返回信息都是底层通过JNI调用上层的回调返回过去的,也就是实现了c/c++与java的交互。这个可能很久以前就有,但对我来说是一个新东西,这里就将java调用c/c++再返回到java这个过程完整的记录下来吧。

 

2.  JAVA调用c/c++

(1)    编写java文件:

编写java有三个地方要编写:首先是编写要加载的so文件,这个文件中包含了即将要调用的本地方法;然后将与c中对应的方法以native的关键字标示出来,标示这是一个本地方法调用;最后再java中调用这个本地方法。例如实现一个a+b;

1.  static {  //加载so文件

2.         System.loadLibrary(“XXX_so_name”);  

3.  }

4.   

5.   

6.   public native int add(int x, int y);//定义本地方法

7.   

8.   int result = add(x,y);//调用本地方法

9.   

 

 

 

(2)    编写C文件:

编写C文件实现上述定义的native方法,主义文件中要包含jni.h头文件。

1.  #include <string.h>  

2. #include <jni.h>

3.  

4.  int add(int x,int y) {  

5. return x+y;  

6. 

7.  

 

(3)      编写mk文件:

由于我们在这里都是在android的环境下做的实验,所以mk文件直接编写为Android.mk文件。编写格式如下:

 

1.   LOCAL_PATH:= $(call my-dir)

2.   include $(CLEAR_VARS)

3.   LOCAL_MODULE    := XX_so_name

4.   LOCAL_SRC_FILES := \

5.      XXXName.c   \

 

(4)    编译测试:

 

3.  c/c++调用JAVA

(1)    编写java调用JNI:

为了方便测试,这里将通过android中的java调用C的方法,实际上C的方法的实现是调用了另一个java的方法。所以前面的部分仍然是java调用C/C++的实现。

 

(2)    编写C调用的JAVA文件:

编写C调用的JAVA文件,里面就实现一个void方法,即没有返回值得方法。,这个地方根据JNI的规范,对不同返回值不同修饰符的方法都有对应的方式。只要按照写即可,这里用最简单的void方法。

8.  public class TestProvider {   

9.  

10.   public void sayHello(String msg) {

11.  LogUtils.printWithSystemOut("Call From C Java Not Static              Method " + msg); 

12. 

13.LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Not Static Method " + msg);

14.

15. 

 

(3)      编写C文件:

在C文件中需要将上述的JAVA文件的方法和类名都获取到,然后再通过获取的类和方法调用上述的方法,也可以带值回传(这里就是在android4.4版本中的一些framework层将底层的一些错误通过这种方式反馈到java的回调函数中,java回调函数可以根据这些返回值做逻辑操作,目前看的MediaPlayer和Camera都有这样的调用):

1.  #include "Provider.h"  

2. #include <android/log.h>  

3.    

4. extern JNIEnv* jniEnv;  

5.    

6. jclass TestProvider;  

7.  jobject mTestProvider;  

8. jmethodID getTime;  

9.  jmethodID sayHello;  

10.  

11. int GetProviderInstance(jclass obj_class);  

12.  

13. /** 

14. * 初始化 类、对象、方法 

15.  */  

16.int InitProvider() {  

17.   

18.    __android_log_print(ANDROID_LOG_INFO, "JNIMsg""InitProvider Begin  1" );  

19.   

20.    if(jniEnv == NULL) {  

21.         return 0;  

22.    }  

23.   

24.    if(TestProvider == NULL) {  

25.         TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");  

26.        if(TestProvider == NULL){  

27.             return -1;  

28.        }  

29.         __android_log_print(ANDROID_LOG_INFO, "JNIMsg""InitProvider Begin  2 ok" );  

30.    }  

31.   

32.    if (mTestProvider == NULL) {  

33.         if (GetProviderInstance(TestProvider) != 1) {  

34.            (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);  

35.             return -1;  

36.        }  

37.         __android_log_print(ANDROID_LOG_INFO, "JNIMsg""InitProvider Begin  3 ok" );  

38.    }  

39.   

40.    if (getTime == NULL) {  

41.         getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");  

42.        if (getTime == NULL) {  

43.             (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);  

44.            (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);  

45.             return -2;  

46.        }  

47.         __android_log_print(ANDROID_LOG_INFO, "JNIMsg""InitProvider Begin  4 ok" );  

48.    }  

49.   

50.    if (sayHello == NULL) {  

51.         sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V");  

52.        if (sayHello == NULL) {  

53.             (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);  

54.            (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);  

55.             (*jniEnv)->DeleteLocalRef(jniEnv, getTime);  

56.            return -3;  

57.         }  

58.        __android_log_print(ANDROID_LOG_INFO, "JNIMsg""InitProvider Begin  5 ok" );  

59.     }  

60.  

61.     __android_log_print(ANDROID_LOG_INFO, "JNIMsg""InitProvider Begin  6" );  

62.    return 1;  

63.   

64.}  

65.   

66.int GetProviderInstance(jclass obj_class) {  

67.   

68.    if(obj_class == NULL) {  

69.         return 0;  

70.    }  

71.   

72.    jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, obj_class,  

73.             "<init>""()V");  

74.  

75.     if (construction_id == 0) {  

76.        return -1;  

77.     }  

78.  

79.     mTestProvider = (*jniEnv)->NewObject(jniEnv, obj_class,  

80.            construction_id);  

81.   

82.    if (mTestProvider == NULL) {  

83.         return -2;  

84.    }  

85.   

86.    return 1;  

87. }  

88.  

89. /** 

90. * 获取时间 ---- 调用 Java 方法 

91.  */  

92.   

93./** 

94.  * SayHello ---- 调用 Java 方法 

95. */  

96. void SayHello() {  

97.    if(TestProvider == NULL || mTestProvider == NULL || sayHello == NULL) {  

98.         int result = InitProvider() ;  

99.        if(result != 1) {  

100.                  return;  

101.             }  

102.          }  

103.       

104.          jstring jstrMSG = NULL;  

105.         jstrMSG =(*jniEnv)->NewStringUTF(jniEnv, "Hi,I'm From C");  

106.          __android_log_print(ANDROID_LOG_INFO, "JNIMsg""SayHello Begin" );  

107.         (*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);  

108.          __android_log_print(ANDROID_LOG_INFO, "JNIMsg""SayHello End" );  

109.       

110.          (*jniEnv)->DeleteLocalRef(jniEnv, jstrMSG);  

111.     }  

 

(4)    编译mk文件:

 

1.  LOCAL_PATH := $(call my-dir)  

2.   

3.  include $(CLEAR_VARS)  

4.   

5.  LOCAL_C_INCLUDES := $(LOCAL_PATH)/include  

6. LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog  

7.    

8.   

9.  LOCAL_MODULE    := NDK_04  

10.LOCAL_SRC_FILES := \  

11. CToJava.c \  

12.Provider.c  

13.   

14.include $(BUILD_SHARED_LIBRARY)

 

(5)    ps需要补充的留白……

4.  总结

JNI和NDK在android中举足轻重,如果想编写高性能的代码,如果想让自己的app某些部分更好的隐藏起来,使用jni的方式不失为一个好的方法。因此将这两个工具熟练度的掌握在后续的学习工作中都将是高能的。而且在混编时代的来临,懂得这种技术也将会更好的适应环境。慢慢学习吧,目前就是希望基础打捞一点,然后找更多的机会锻炼自己的能力,不断的加深实践调高自己。

继续努力,Keep moving!!!

0 0
原创粉丝点击