基于 Android NDK 的学习之旅----- C调用Java
许多成熟的C引擎要移植到Android 平台上使用 , 一般都会 提供 一些接口, 让Android sdk 和 jdk 实现。
下文将会介绍 C 如何 通过 JNI 层调用 Java 的静态和非静态方法。
1、主要流程
1、 新建一个测试类TestProvider.java
a) 该类提供了2个方法
b) 一个静态的方法,一个非静态的方法
2、 JNI中新建Provider.c
a) 该文件中需要把Java中的类TestProvider映射到C中
b) 把TestProvider的两个方法映射到C中
c) 新建TestProvider 对象
d) 调用两个方法
3、 Android 上层 调用 JNI层
4、 JNI层调用C层
5、 C 层调用 Java 方法
2、设计实现
1、界面设计如下:
老样子,很搓,不过实用,嘿嘿
代码不在这贴出了,有需要的兄弟直接到文章结束部分下载。
2、 关键代码说明
C中定义映射的类、方法、对象
jclass TestProvider;
jobject mTestProvider;
jmethodID getTime;
jmethodID sayHello;
C 中映射 类
TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");
C中新建对象
jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, TestProvider,"<init>", "()V");
TestProvider mTestProvider = (*jniEnv)->NewObject(jniEnv, TestProvider,construction_id);
C 中映射方法
静态:
getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");
非静态:
sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V");
C 中调用 Java的 方法
静态:
(*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);
非静态:
(*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
注意 GetXXXMethodID 和 CallXXXMethod 。
第一个XXX 表示的是映射方法的类型,如: 静态 跟非静态
第二个 XXX 表示 调用方法的返回值 ,如:Void,Object,等等。(调用静态方法的时候Call后面要加Static)
详细 映射方法 和 调用方法 请参考 JNI 文档 ,这个很重要 !
3、 Java 上层 关键代码
TestProvider.Java 的两个方法
package com.duicky; /** * * * @author luxiaofeng <454162034@qq.com> * */ public class TestProvider { public static String getTime() { LogUtils.printWithSystemOut( "Call From C Java Static Method" ); LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Static Method" ); return String.valueOf(System.currentTimeMillis()); } public void sayHello(String msg) { LogUtils.printWithSystemOut( "Call From C Java Not Static Method :" + msg); LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Not Static Method :" + msg); } } |
4、 Android.mk 文件 关键代码
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog LOCAL_MODULE := NDK_04 LOCAL_SRC_FILES := \ CToJava.c \ Provider.c include $(BUILD_SHARED_LIBRARY) |
老样子,不说了,你懂的。 如果不懂,嘎嘎,那就请点击Android.mk 文件 简介
5、 JNI文件夹下文件
Provider.h
#include <string.h> #include <jni.h> void GetTime() ; void SayHello(); |
Provider.c
#include "Provider.h" #include <android/log.h> extern JNIEnv* jniEnv; jclass TestProvider; jobject mTestProvider; jmethodID getTime; jmethodID sayHello; int GetProviderInstance(jclass obj_class); /** * 初始化 类、对象、方法 */ int InitProvider() { __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 1" ); if (jniEnv == NULL) { return 0; } if (TestProvider == NULL) { TestProvider = (*jniEnv)->FindClass(jniEnv, "com/duicky/TestProvider" ); if (TestProvider == NULL){ return -1; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 2 ok" ); } if (mTestProvider == NULL) { if (GetProviderInstance(TestProvider) != 1) { (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); return -1; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 3 ok" ); } if (getTime == NULL) { getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime" , "()Ljava/lang/String;" ); if (getTime == NULL) { (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider); return -2; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 4 ok" ); } if (sayHello == NULL) { sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello" , "(Ljava/lang/String;)V" ); if (sayHello == NULL) { (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider); (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider); (*jniEnv)->DeleteLocalRef(jniEnv, getTime); return -3; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 5 ok" ); } __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "InitProvider Begin 6" ); return 1; } int GetProviderInstance(jclass obj_class) { if (obj_class == NULL) { return 0; } jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, obj_class, "<init>" , "()V" ); if (construction_id == 0) { return -1; } mTestProvider = (*jniEnv)->NewObject(jniEnv, obj_class, construction_id); if (mTestProvider == NULL) { return -2; } return 1; } /** * 获取时间 ---- 调用 Java 方法 */ void GetTime() { if (TestProvider == NULL || getTime == NULL) { int result = InitProvider(); if (result != 1) { return ; } } jstring jstr = NULL; char * cstr = NULL; __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "GetTime Begin" ); jstr = (*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime); cstr = ( char *) (*jniEnv)->GetStringUTFChars(jniEnv,jstr, 0); __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "Success Get Time from Java , Value = %s" ,cstr ); __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "GetTime End" ); (*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr); (*jniEnv)->DeleteLocalRef(jniEnv, jstr); } /** * SayHello ---- 调用 Java 方法 */ void SayHello() { if (TestProvider == NULL || mTestProvider == NULL || sayHello == NULL) { int result = InitProvider() ; if (result != 1) { return ; } } jstring jstrMSG = NULL; jstrMSG =(*jniEnv)->NewStringUTF(jniEnv, "Hi,I'm From C" ); __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "SayHello Begin" ); (*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG); __android_log_print(ANDROID_LOG_INFO, "JNIMsg" , "SayHello End" ); (*jniEnv)->DeleteLocalRef(jniEnv, jstrMSG); } |
CToJava.c
#include <string.h> #include <android/log.h> #include <jni.h> #include "Provider.h" JNIEnv* jniEnv; /** * Java 中 声明的native getTime 方法的实现 */ void Java_com_duicky_MainActivity_getTime(JNIEnv* env, jobject thiz) { if (jniEnv == NULL) { jniEnv = env; } GetTime(); } /** * Java 中 声明的native sayHello 方法的实现 */ void Java_com_duicky_MainActivity_sayHello(JNIEnv* env, jobject thiz) { if (jniEnv == NULL) { jniEnv = env; } SayHello(); } |
3、运行效果
1、点击 “C调用java静态方法”按钮
C成功调用了Java中的getTime 方法,通过C方法打印出上层调用得到的时间,并且上层成功吐司出调用信息出来。
2、点击 “C调用java非静态方法”按钮
C成功调用了sayHello 方法, 并成功接收到 C 传递的参数,和 吐司出相对应的信息
4、C调用Java注意点
a)
C 映射java 方法时 对应的签名
getTime = (*jniEnv)->GetStaticMethodID(jniEnv,
TestProvider, "getTime","()Ljava/lang/String;");
故事情节还没发展这么快,下一章才会专门介绍下这个签名的使用
b)映射方法的时候需要区别静态和非静态GetStaticMethodID,GetMethodID
c)调用的时候也需要区分CallStaticObjectMethod,CallVoidMethod 而且还需要区分返回值类型
有不理解的兄弟请留言,个人技术有限,有讲错的地方请大牛们指出,讲的不够全面的请多多包涵,谢谢,
点击下载源码
C调用Java例子
本文出自 duicky 博客 , 转载请注明出处 http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html
基于 Android NDK 的学习之旅----- C调用Java的更多相关文章
- 【转】基于 Android NDK 的学习之旅-----数据传输(引用数据类型)
原文网址:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/20/2147086.html 基于 Android NDK 的学习之旅-----数据 ...
- 基于 Android NDK 的学习之旅-----环境搭建
工欲善其事 必先利其器 , 下面介绍下 Eclipse SDK NDK Cygwin CDT 集成开发环境的搭建. 1.Android 开发环境搭建 Android开发环境搭建不是重点,相信看此文章的 ...
- 基于 Android NDK 的学习之旅-----序言
前些日子做了个Android项目, 引擎层 用C的, 准备写这个系类的文章,借此跟朋友来分享下我NDK开放的经验以及自己知识的总结和备忘.希望能给需要这方面资料的朋友提供一定的帮助. 主要涉及到: ...
- 基于 Android NDK 的学习之旅-----HelloWorld
Hello World作为所有编程语言的起始阶段,占据着无法改变的地位,所有中/英/法/德/美……版本的编程教材中,hello world总是作为第一个TEST记录于书本之中,所有的编程第一步就在于此 ...
- 基于 Android NDK 的学习之旅-----JNI LOG 打印
程序都是调出来的. 下面我介绍下JNI层的log打印方法的使用,类似与Android sdk提供的log 1.Android 应用层 MainActivity.java 主要功能代码 a) ...
- 基于 Android NDK 的学习之旅-----数据传输(引用数据类型)
接着上篇文章继续讲.主要关于引用类型的数据传输,本文将介绍字符串传输和自定义对象的传输. 1.主要流程 1. String 字符串传输 a) 上层定义一个native的方法,需要一个 ...
- 基于 Android NDK 的学习之旅-----Java 调用C
随便谈谈为什么要Java调用C 吧: 我认为: 1. 有些公司开发Android项目的时候, 许多组件功能可能是C中已经实现了,所以我们没必要同样的功能又在java中实现一遍.例如我之前做的一个项目 ...
- 基于 Android NDK 的学习之旅-----Android.mk 介绍
一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...
- 基于 Android NDK 的学习之旅-----资源释放
做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概念(GC直接帮忙回收),后查询原因才知道是因为JNI 有些对 ...
随机推荐
- ListCtrl添加右键菜单(在对话框类中)
在对话框类中如何添加NM_RCLICK消息: ListCtrl控件右键单击选择属性 在右侧属性栏中选择控件事件 在控件事件中找到NM_RCLICK并添加 完成,写代码
- UVA 11557 - Code Theft (KMP + HASH)
UVA 11557 - Code Theft 题目链接 题意:给定一些代码文本.然后在给定一个现有文本,找出这个现有文本和前面代码文本,反复连续行最多的这些文本 思路:把每一行hash成一个值.然后对 ...
- libcurl 通过http协议下载文件并显示下载进度
vc6 测试工程下载地址:http://download.csdn.net/detail/mtour/8068053 代码如下: size_t my_write_func(void *ptr, siz ...
- (转)看懂类图——UML类图基础
类图 要学懂设计模式,就需要先看得懂类图,类与类之间的关系是学习设计模式的基础,而在软件工程中,类与类之间的关系是通过UML中的类图来体现. 这篇笔记包含的不会是类图的所有东西,包含的只是各个类之间的 ...
- Fragment Summary 1/2
转自:http://blog.csdn.net/lmj623565791/article/details/37970961 自从Fragment出现,曾经有段时间,感觉大家谈什么都能跟Fragment ...
- Altium Designer中的粉红色网格和绿色框框
- ES6的学习之路(基础知识总结)
1. 变量声明 1).let 1)使用let定义的变量不会进行"变量提升" console.log(a);//Uncaught ReferenceError: a is not d ...
- Hamming correct
从数的最左边开始,并标记为1 将2的平方的位置留出来,做为校验位例如,8位2进制数10011010===>_ _ 1 _ 0 0 1 _ 1 0 1 0 位置1用来校验最右边的位位1的位置1 3 ...
- Java ThreadLocal Example(java中的ThreadLocal例子)
Java ThreadLocal is used to create thread local variables. We know that all threads of an Object sha ...
- NLP系列(1)_从破译外星人文字浅谈自然语言处理的基础
作者:龙心尘 &&寒小阳 时间:2016年1月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50543337, h ...