Android使用JNI
来源:互联网 发布:威戈背包知乎 编辑:程序博客网 时间:2024/05/17 23:42
参考:
JNI官方:http://developer.android.com/training/articles/perf-jni.html
JNI入门:http://blog.sina.com.cn/s/blog_5f35912f0100vvnn.html
http://blog.sina.com.cn/s/blog_5de73d0b0101chk1.html
http://wenku.baidu.com/view/d670c823a5e9856a56126051.html
Java中的native函数与jni中的C函数是怎样联系起来的:
(1)Test.java,分别代表了四种java函数:非static无参函数、static无参函数、非static有参函数、static有参函数。
package com.jeremyfeinstein.slidingmenu.example;public class Test {public native String test();public native static void test2();public native void test3(String str);public native static void test4(String str);}
(2)使用javah.exe生成com_jeremyfeinstein_slidingmenu_example_Test.h,点击:(关于javah.exe和NDK的配置请参见:ANDROID 一键搞定JNI创建C头文件),如下所示:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_jeremyfeinstein_slidingmenu_example_Test */#ifndef _Included_com_jeremyfeinstein_slidingmenu_example_Test#define _Included_com_jeremyfeinstein_slidingmenu_example_Test#ifdef __cplusplusextern "C" {#endif/* * Class: com_jeremyfeinstein_slidingmenu_example_Test * Method: test * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test(JNIEnv *, jobject);/* * Class: com_jeremyfeinstein_slidingmenu_example_Test * Method: test2 * Signature: ()V */JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test2(JNIEnv *, jclass);/* * Class: com_jeremyfeinstein_slidingmenu_example_Test * Method: test3 * Signature: (Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test3(JNIEnv *, jobject, jstring);/* * Class: com_jeremyfeinstein_slidingmenu_example_Test * Method: test4 * Signature: (Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test4(JNIEnv *, jclass, jstring);#ifdef __cplusplus}#endif#endif在当前工程目录的jni目录下自动生成文件com_jeremyfeinstein_slidingmenu_example_Test.h,这个.h文件的名称组成是:java类Test的全称(包名+类名),jni就是通过这个名称组合来找到java类对应C/C++文件的,进而再根据C/C++函数名称来找到对应的调用函数,生成的具有jni格式的C/C++函数名称组成是:Java_包名_java类名_java类中的对应方法名(Java_Java类全称_Java类中对应的方法名),方法参数组成规则是:每个函数的第一个参数都是JNIEvn *类型的;如果函数在Java类中是static的函数,则第二个参数必须是jclass类型,代表当前Java类,如果函数在Java类中是非static类型的函数,则第二个参数必须是jobject类型的,代表的是当前Java类的实例对象;剩下的参数就和java类中的函数的参数一一对应了。
(3)在当前工程目录下的jni目录中找到生成的com_jeremyfeinstein_slidingmenu_example_Test.h,然后再新建一个com_jeremyfeinstein_slidingmenu_example_Test.c文件,并实现com_jeremyfeinstein_slidingmenu_example_Test.h中的所有函数,这里和C/C++的写法一样,只是必须按照jni的格式来写C/C++代码,或者是直接调用已经存在的C/C++代码,这些已经存在的C/C++代码存放的位置也是在当前工程目录下的jni目录中,这样在com_jeremyfeinstein_slidingmenu_example_Test.c中就可以直接遵照JNI标准来调用这部分C/C++代码了。除此之外,还有一点:在具有JNI格式的.c/.cpp文件中可以完全像C/C++文件一样使用C/C++语法,例如可以在.c/.cpp文件中写其他C/C++函数(供其他函数调用),只是这些函数本身必须遵照JNI格式;可以在jni下建立任意的C/C++文件,让程序具有jni格式的C/C++文件调用:
这个地方的test.c和test.h是完全用C/C++语法写的代码,可以在com_jeremyfeinstein_slidingmenu_example_Test.c中进行直接调用;
#include <stdio.h>#include <jni.h>#include "com_jeremyfeinstein_slidingmenu_example_Test.h"JNIEXPORT jstring JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test(JNIEnv *env, jobject obj) {return (**env).NewStringUTF(env, "Say hello frome C to Android !");}JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test2(JNIEnv *env, jclass clz) {}JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test3(JNIEnv *env, jobject obj, jstring str) {}JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test4(JNIEnv *env, jclass clz, jstring str) {}
(4)上面.h和.c都完成之后,就必须在当前目录下写一个Android.mk文件,这个文件类似C/C++里的Makefile文件,但是Makefile中的依赖文件、编译规则等等都已经被Android系统完成了,Android.mk里的规则很简单,我们只需要按照模板修改添加需要编译的.c或.cpp文件和编译最终生成.so名称即可,关于Android.mk详细语法规则参见:http://blog.csdn.net/habbyge/article/details/11267081,这里需要特别注意:Android.mk的存放位置,必须和当前编译的C/C++(JNI格式)文件放在同意目录下。
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE:= testLOCAL_SRC_FILES := com_jeremyfeinstein_slidingmenu_example_Test.cinclude $(BUILD_SHARED_LIBRARY)
(5)之后,就可以使用NDK编译生成libtest.so文件了,点击:,这个文件被生成在当前工程目录下的libs/armeabi目录下(libs/armeabi/libtest.so),自此就可以在Java中使用这个C/C++代码了,具体使用方法,参见:http://blog.csdn.net/habbyge/article/details/19857113。
补充:
以上主要是介绍在Java中调用C/C++代码,下面说明C/C++调用Java代码的方法:
C++中调用Java会比较麻烦一些,因为需要在C++中获取Java的运行环境,并寻找我们要用的类和方法。首先我们需要了解几个概念
JavaVM:这个代表java的虚拟机。所有的工作都是从获取虚拟机的接口开始的,如何获取这个接口呢?我们之前导入C的组件时调用了:System.loadLibrary(“test”);
调用该方法时,java会先调用该组件的JNI_OnLoad()函数.其用途有二:
一是:告诉java VM此C组件使用那一个JNI版本。如果你没有提供JNI_OnLoad()函数,VM会默认使用最老的JNI 1.1版本。由于新版的JNI做了许多扩充,如果需要使用JNI的新版功能,例如JNI 1.4的java.nio.ByteBuffer,就必须藉由JNI_OnLoad()函数来告知VM。
二是:由于VM执行到System.loadLibrary()函数时,就会立即先呼叫JNI_OnLoad(),所以C组件的开发者可以藉由JNI_OnLoad()来进行C组件内的初期值之设定,也就是获取JavaVM接口。
如:
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JniHelper::setJavaVM(vm); // 获取JavaVM接口
return JNI_VERSION_1_4; // 告知java使用什么版本的VM
}
JNIEnv: 它代表Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作。如,创建Java类得对象,调用Java对象的方法,获取Java对象的属性等。通过之前获得的JavVM我们可以获取JNIEnv:
static bool getEnv(JNIEnv **env) {
bool bRet = false;
do {
if (JAVAVM->GetEnv((void**)env, JNI_VERSION_1_4) != JNI_OK) {
LOGD("Failed to get the environment using GetEnv()");
break;
}
if (JAVAVM->AttachCurrentThread(env, 0) < 0) {
LOGD("Failed to get the environment using AttachCurrentThread()");
break;
}
bRet = true;
} while (0);
return bRet;
}
有了上面的准备,下面我们就可以开始调用java的东西了:
一:获取对象的类id
我们只要知道类的名字就可以通过JNIEnv来获取classid
jclass classID = pEnv->FindClass(className);
二:获取要调用的方法id,包括静态和普通方法。
三:调用方法,同样包括静态和普通。
pEnv ->CallStatic***Method(classID,methodID);
pEnv ->Call***Method(classID,methodID);
函数签名是一个字符串:"(M)N",括号中的内容是函数的参数类型,括号后面表示函数的返回值。
字符
V
Z
I
J
D
F
B
C
S
[I
[F
[B
[C
[S
[D
[J
[Z
附:函数属性签名规则:
在GetMethodID最后一个参数是签名字符串,用来标示java函数和成员的唯一性。因为java中存在重载函数,所以一个函数名不足以唯一指定一个函数,这时候就需要签名字符串来指定函数的参数列表和返回值类型了。具体的每一个字符的对应关系如下数组则以”["开始,用两个字符表示
- android中使用JNI
- Android JNI 使用
- android 如何使用jni
- android 使用jni
- Android Jni 使用篇
- linux android 使用JNI
- Android JNI的使用
- android jni 使用过程
- Android之JNI使用
- Android使用JNI
- Android JNI使用例子
- Android Jni 使用
- Android中jni使用
- android jni的使用
- android studio JNI使用
- Android Studio使用JNI
- Android Jni使用案例
- android studio使用jni
- Java Socket网络编程常见异常
- 输入两个整数 n 和 m,从数列1,2,3…….n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来
- 第二章 身份验证
- 【LeetCode】Maximum Depth of Binary Tree && Minimum Depth of Binary Tree
- Java 可变参数
- Android使用JNI
- 获取设备环境句柄的方法
- Hibernate之Query查询的list()方法和iterator()方法的区别
- jquery serializeObject() 读取
- django+ajaxgold
- CPU的常见故障及处理方法
- HDU-1482-Counterfeit Dollar
- Android实现程序前后台切换效果(类似QQ后台运行)
- oracle的正则表达式