android JNI 技术初步探索 ----- 效率

JNI 全称 java native interface,即本地接口, 是一种在 java 中调用本地 C/C++ 方法的技术;

使用 JNI 编程有好处也有坏处,今天我们来探索一下 JNI 编程的效率问题;

 

使用 JNI 编程的实现过程

准备工作

配置 ndk,打开 project structure, 在如下位置有一个配置 Android NDK location

如果没有可以下载后再配置

 

 

1、编写一个 java 类,并在 java 类中申明 native 方法

public class TestJNI {
    static native int add(int a,int b);  
}

申明了一个 add 方法

 

2、打开 dos 命令窗口,进入到 TestJNI 类所在的文件夹,执行 javac 文件名.java 将 TestJNI 类变异成 .class 文件

3、使用 cd .. 命令退回到 src/main/java 目录, 执行 javah -jni 包名.类名,将 .class 文件编译成 .h 文件

执行完之后,会在 src/main/java 目录下生成一个 com_study_hugy_testjnidemo_NativeJNI.h 文件,文件内容如下

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_study_hugy_testjnidemo_NativeJNI */

#ifndef _Included_com_study_hugy_testjnidemo_NativeJNI
#define _Included_com_study_hugy_testjnidemo_NativeJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_study_hugy_testjnidemo_NativeJNI
 * Method:    jieCheng
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_study_hugy_testjnidemo_NativeJNI_add
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

主要就是我们 编辑的 add 方法接口

 

4、在 scr/main/java 下新建一个 jniFolder "jni",并将第三步得到的文件复制进去,并且新建一个文件 NativeJNI.c, 当然名字随你的意思取, 这个类的主要目的就是实现 .h 文件中的方法

#include<com_study_hugy_testjnidemo_NativeJNI>

JNIEXPORT jint JNICALL Java_com_study_hugy_testjnidemo_NativeJNI_jieCheng
  (JNIEnv *env, jclass jobj, jint a, jint b) {
    return a+b;
}

 

5、在项目的 gradle.properties 文件中加入 

android.useDeprecatedNdk=true

并且在 app 的 build.gradle 文件中加入

android {
    compileSdkVersion 26
    defaultConfig {
        ...
        ndk {
            moduleName "NativeJni"//指定生成的so文件名
            abiFilters  "armeabi-v7a", "x86"//cpu的类型
        }
    }
        ...
    sourceSets { main { jni.srcDirs = ['src/main/jni',     'src/main/jni/'] } }
}

同步资源文件,然后 rebuild 工程,这时会发现一个错误

这个错误是说 android.useDeprecatedNdk 已经不再支持了,并且会在 android studio 的下一个版本中移除,震惊脸,WTF,不支持了,玩犊子啊。

不要急,接着往下看,看到最后一句话,To continue using ... ,set android.deprecatedNdkConpieLease=XXX ,哦, 删掉  android.useDeprecatedNdk=true, 以 android.deprecatedNdkConpieLease=XXX 替代, 同步资源文件 ,重新 rebuild ,完美通过,这时你会在build/intermediate/ndk 目录下发现生成的 so 文件

 

最后就是使用了

System.loadLibrary("NativeJNI");
System.out.println(NativeJNI.add(3,4));

 

到这里 JNI 技术的基本用法就基本掌握了,回到最初的问题,探索 JNI 技术的优点之效率;

 

如何探索呢,我用到的办法是对一个很大的数 for 循坏,查看循环前后的时间差

JNI 方法如下

#include<com_study_hugy_testjnidemo_NativeJNI.h>
#include<time.h>

JNIEXPORT jint JNICALL Java_com_study_hugy_testjnidemo_NativeJNI_jieCheng
  (JNIEnv *env, jclass jobj, jint num) {
    long time_1;
    time(&time_1);

    int i;
    int result = 1;
    for(i = 1; i <= num; i++) {
        result = result * i;
    }
    long time_2;
    time(&time_2);

    return time_2 - time_1;
  }

这个方法得到的时间是 s, 所以传入的数最好 大一些;

 

java 方法就比较简单了

public int jiecheng(int num) {
  long  time_1 = SystemClock.currentThreadTimeMillis();
  int result = 1;
  for(int i = 1; i<=num; i++) {
    result *= i;
  }
  long time_2 = SystemClock.currentThreadTimeMillis();
  return time_2 - time_1;  
}

这个方法得到的时间单位是 ms

 

传入 1000000000,发现运行结果如下

(我的电脑)jni 在 1s 之内运算完毕, 而 java 需要 4s ,确实 JNI 的效率比值 java 高不少, 特别是在复杂的运算中。

 其他优点待补充....

 

posted on 2018-03-29 15:32  秦家十月  阅读(695)  评论(0编辑  收藏  举报

导航