在某些情况下,Java编程已经不能满足我们的需要,比如一个复杂的算法处理,这时候就需要用到jni(java native interface)技术;
jni 其实就是java和c/cpp之间进行通信的一个接口规范,java可以调用c/cpp里面的函数,同样,c/cpp也可以调用java类的方法;
jni开发工具ndk的安装:
在最新的ndk版本中,安装ndk很简单,只需要装ndk的路径配置到系统环境变量中即可;
在编译的时候,进入工程根目录;执行命令 ndk-build 即可完成编译;
下面就通过一个例子一步一步的来初步学习jni
一、HelloWorld
新建一个工程,你甚至不需要其它额外的设置,然后在工程中添加一个jni目录,然后就可以开始了;
1.新建一个java类HelloWorld.java
package com.jni; public class HelloWorld { static { System.loadLibrary("helloworld"); } public native String helloworld(); }
在HelloWorld中,定义了一个方法helloworld(),只不过这个方法被申明成了native的,并没有具体的实现,具体功能我们在接下来的cpp文件中实现;
2.在jni目录下添加一个helloworld.cpp
#include <jni.h> #include <Android/log.h> #include <string.h> #ifndef _Included_com_jni_HelloWorld // 1 #define _Included_com_jni_HelloWorld #ifdef __cplusplus // 2 extern "C" { #endif // 2 JNIEXPORT jstring JNICALL Java_com_jni_HelloWorld_helloworld(JNIEnv *, jobject); #ifdef __cplusplus // 3 } #endif // 3 #endif // 1 JNIEXPORT jstring JNICALL Java_com_jni_HelloWorld_helloworld(JNIEnv * env, jobject obj) { return env->NewStringUTF("helloworld"); }
从上面这个cpp文件中可以很明白的看出,它有一个方法,具体包括方法申明和方法实现两个部分;但是相信大家也都看出来了,方法的命令很怪异,怎么这么长的方法名?
我们在这里先思考一个问题,java类中的方法是如何调用c++中的方法的呢?要解决这个问题,就得先来看这个长长的方法名;
其实这是jni的一个规范之一,用于映射java方法和c/c++中的方法对应;
再来看在cpp中定义的函数名:Java_com_jni_HelloWorld_helloworld
其实不难看出,java文件与cpp文件中函数名的配对定义方式为Java + 包名 + java类名 + 方法/函数名,中间用_分隔;其中两个参数分别是:
env:当前该线程的内容,包含线程里面全部内容;
obj:当前类的实例,指.java文件的内容(在该例子中即是HelloWorld类);
这里的helloworld方法,其实就只是返回了一个单词"helloworld";
3.在jni目录下添加一个Android.mk文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := helloworld LOCAL_SRC_FILES := helloworld.cpp include $(BUILD_SHARED_LIBRARY)
4.在命令行下进入工程目录执行 ndk-build 命令,然后运行程序,调用HelloWorld实例的helloworld方法就可以得到它的返回字符串了;
二、jni调用Java类的方法(1)
通过上面的helloworld练手之后,我们来看一下jni调用java类里面的方法的实现;
1.新建设一个MethodCall.java文件如下
public class MethodCall { final String tag = "MethodCall"; static { System.loadLibrary("methodcall"); } public native String jniCallMethod1(); public native String jniCallMethod2(); public native String jniCallStaticMethod(); public void javaMethod1() { Log.e(tag, "javaMethod1"); } public String javaMethod2() { Log.e(tag, "javaMethod2"); return "javaMethod2"; } public static void javaStaticMethod(String input) { Log.e("MethodCall", "" + input); } }
该类有6个方法,其中有3个是java类的方法,另外3个是native方法,3个native方法分别去调用3个java方法;
2.添加三个native方法具体实现 methodcall.cpp