安卓jni调用之C代码中调用Java代码
2015-07-01 13:51
543 查看
C调用Java中的方法
其实就是从java中调用c,从C中调用java的方法,可以看做是一个回调Java中没有参数的方法
1.在java中写一个本地方法[code]public native void methodInC();
2.使用命令提示符进入到项目下的bin/classes目录下,使用javah 类的全路径 命令得到本地方法的头文件
3.在项目上点右键–>Android Tools–>Add Native Support,给我们的C代码起一个名字,点确定,会自动生成一个jni的目录和c代码(一般生成的是.cpp,把后缀改为.c)
4.自动生成的Android.mk文件中的编译源文件是.cpp,改为c(如果第三步没有改,则不需要改)
[code]#指定编译的文件夹 指定当前文件目录 LOCAL_PATH := $(call my-dir) #编译器会定义很多的临时变量,中间变量,最好清空所有的中间变量。 include $(CLEAR_VARS) #编译出来模块的名称(编译后的名字,也就是存放于libs目录下的名字,不带扩展名) LOCAL_MODULE := hello # 编译的源代码的名称(要编译的c代码的名称,带扩展名) LOCAL_SRC_FILES := hello.c #编译一个动态库 include $(BUILD_SHARED_LIBRARY)
5.如果需要在除arm处理器的其它机型上使用,需要在jni目录下创建一个Application.mk文件(如果只是在arm下使用,可以跳过此步骤),需要哪一个处理器,就配置哪一个,不要配置太多,因为生成的文件会很大
[code]APP_ABI := arm x86 mips
6.把ndk安装的目录下的android-ndk-r9b\platforms\android-16\arch-arm\usr\include/jni.h复制到项目的jni目录下(平台就现在版本没有任何区别,哪一个版本下的都可以)
7.写C代码
[code]#include <jni.h> #include "stdio.h" #include "com_itheima_calljava_DataProvider.h" /** * 用C代码调用java代码中的方法,去发送一条短信 */ JNIEXPORT void JNICALL Java_com_itheima_calljava_DataProvider_methodInC (JNIEnv* env, jobject obj){ //第一步:找到要调用的方法的class字节码文件 jclass clazz = (*env)->FindClass(env,"com/itheima/calljava/DataProvider"); //第二步:找到这个类中的方法.参数依次为:JVM虚拟机环境、class对象、方法名、方法签名(返回值+方法的形参) jmethodID mid = (*env)->GetMethodID(env,clazz,"methodInjava","()V"); //第三步:调用这个方法 (*env)->CallVoidMethod(env,obj,mid); }
8.在要调用本地方法的类中使用静态代码块的方式加载生成的c代码库
[code]static{ //这个名字是在Android.mk中的LOCAL_MODULE的值,不带前缀,不带扩展名 System.loadLibrary("hello"); }
9.只要在java中调用本地方法methodInC即可
注: Java中的被C调用的方法
[code]/** * 让C调用此方法,发送一条短信 */ public void methodInjava(){ Log.i(TAG,"-------------------------"); //创建短信管理对象 SmsManager smsManager = SmsManager.getDefault(); //发送一条文本短信 smsManager.sendTextMessage("5556", null, "hello 5556", null, null); }
调取静态方法(C中的代码,其它没区别)
[code]/** * 用C代码去调用java中的静态方法 */ JNIEXPORT void JNICALL Java_com_itheima_calljava_DataProvider_methodInC03 (JNIEnv * env, jobject obj){ //1.查找以class字节码文件 jclass clazz = (*env)->FindClass(env,"com/itheima/calljava/DataProvider"); //2.查找到方法 jmethodID mid = (*env)->GetStaticMethodID(env,clazz,"staticMethodJava","()V"); //3.调用该静态方法 (*env)->CallStaticVoidMethod(env,clazz,mid); }
调取带参数的方法(传入String,)
[code]/** * 用C代码去调用java代码中的方法,拼接一个从C传入的字符串 */ JNIEXPORT void JNICALL Java_com_itheima_calljava_DataProvider_methodInC02 (JNIEnv * env, jobject obj) { //1.查找到Class jclass clazz = (*env)->FindClass(env,"com/itheima/calljava/DataProvider"); //2.查找到方法 jmethodID mid = (*env)->GetMethodID(env,clazz,"methodInjava02","(Ljava/lang/String;)Ljava/lang/String;"); //3.调用方法 (*env)->CallObjectMethod(env,obj,mid,(*env)->NewStringUTF(env,"小志")); }
调取java中的本地方法和被C调用的方法不在同一个类中
[code]/** * 用C代码调用java代码中的方法,去发送一条短信(注意:这个实现的是MainActivity中的本地方法) */ JNIEXPORT void JNICALL Java_com_itheima_calljava_MainActivity_callMethodInC04 (JNIEnv * env, jobject obj){ //第一步:找到要调用的方法的class字节码文件 jclass clazz = (*env)->FindClass(env,"com/itheima/calljava/DataProvider"); //第二步:找到这个类中的方法.参数依次为:JVM虚拟机环境、class对象、方法名、方法签名(返回值+方法的形参) jmethodID mid = (*env)->GetMethodID(env,clazz,"methodInjava","()V"); //由于要调用的方法不是MainActivity(当前对象)中的方法,也就不能使用当前的obj,要创建该方法所在类中的对象 //使用该类clazz字节码文并 使用默认的构造方法创建该对象(没有参数的构造) jobject jobj = (*env)->AllocObject(env,clazz); //第三步:调用这个方法 (*env)->CallVoidMethod(env,jobj,mid); }
注意事项
一般在写本地方法时,都会单独的放在一个单独的类中,方便管理,不容易出错。注意FindClass这个方法的使用,传入的类的全路径是用/分隔的
方法签名的获取(在命令提示符下)
进入到项目的bin/classes目录下
使用javap -s 类的全路径
JNIEnv:代表当前的jvm虚拟机环境
jobject:代表本地方法所在的类(也就是本地方法的调用者)
相关文章推荐
- struts2中s:select标签的使用
- java 检测一个URL地址是否有效
- 【Java基础学习笔记】输入输出流之Reader
- Shortest Palindrome leetcode-java
- Embeded Jetty
- java之URL类
- Java根据生日得出是十二星座的哪一个星座
- Android开发周报:Android Studio取代Eclipse,MVP架构解析
- Java学习之字符串(下)
- spring注解 @PropertySource 配置数据源
- 《Java程序设计》实训每天一博文之第三天
- Struts2(十)标签
- Eclipse快捷键 10个最有用的快捷键
- JAVA面向对像基础之——抽像类和接口
- Java 归并排序
- MyEclipse + Maven开发Web工程的详细配置过程
- eclipse 配置maven web项目
- Java 递归解决 "汉诺塔" 问题
- Java Jersey2使用总结
- Java:Math类中的常用方法