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!!!
- Android内核学习之二------JNI的使用
- android之JNI的使用
- Android之JNI的使用
- android JNI学习二
- Android JNI学习之javah命令的正确使用 转
- Android JNI学习之javah命令的正确使用
- Android学习之 JNI
- Android学习之 JNI
- Android学习之JNI
- android JNI学习之五 JNI中常用的方法
- android JNI学习之六 JNI的一个框架
- android JNI学习之二 调用第三方动态库
- Android之JNI使用
- 我的Android NDK之旅(二),使用ndk-build构建Jni
- Android中JNI的使用之HelloWorld
- (二)内核锁的使用之信号量
- android JNI学习之----JNI功能
- Android JNI学习之---JNI开发流程
- WNDCLASS中cbClsExtra和cbWndExtra区别及其用法
- jQuery.Autocomplete 自动完成
- Scrapy 学习笔记(一)
- CodeForces 115E Linear Kingdom Races(线段树 + DP)
- linux内核内存分配(二、struct slab和struct kmem_cache)
- Android内核学习之二------JNI的使用
- 黑马程序员——Java基础——构造方法,static关键字,以及继承的详解
- (一〇九)UIButton的使用技巧 -imageView、titleLabel、圆角等
- Valid Anagram
- nginx的学习笔记
- linux 进程间通信 使用信号量
- 树莓派实战4:配置一小时发送一次邮件
- YUV格式学习:NV12和YUV420P格式互换
- 89. Gray Code