android艺术开发探索之jni,NDK开发

来源:互联网 发布:ecshop导出淘宝数据包 编辑:程序博客网 时间:2024/06/15 17:06

android艺术开发探索之jni,NDK开发

应用场景:
比如我们公司的机器人,上位机是一个平板,下位机是就是各种电路板,平板上发指令让机器人前进,那么下位机收到指令后就控制机器人前进,下位机的算法是专门的ai工程师写的,用c或者c++,上位机是由我们这些android工程师写的,用的java,如何用java的方法去调用他们写的底层算法,这之间之间的沟通就用到了jni,是他们提供了一些本地接口,封装在一个.so文件中然后供我们来调用。

  • 第一步:先装环境,把ndk装好并配置相应的环境变量,不会的百度。
  • 第二步:在java类中加载.so库,并申明我们想要调用的c++函数,这里以demo-Sum为例:
public class Sum {    //demo是一个求和的例子,使用ndk生成的.so的名字我命名的叫JNISum,用loadLibrary方法加载.so库,这样我们就可以调用里面的c++方法了。    static {        System.loadLibrary("JNISum");    }    //当使用C++调用java非静态方法的时候,需要构造类的对象    public Sum()    {        Log.e("TEST","Sum Constructor");    }    //java调用c++里面的getSum方法。c++里面有一个getSum方法的实现,这里是写一个申明,跟抽象方法很相似,只有方法名不见方法体,方法体在c++里面,需要使用native关键字做申明    public native int getSum(int x, int y);    //c++调用就java的静态getSub方法,因此这个我们把getSub实现,让c++调用    public static int getSub(int x,int y){        return x-y;    }    //c++调用就java的非静态getSub方法,因此这个我们把getMult实现,让c++调用    public int getMult(int x,int y){        return x*y;    } }
  • 第三步:在cmd命令提示符中进入Sum类所在的路径下先生成Sum.class文件,再生成.h文件,然后对着modle的下的java文件夹新建jni文件夹,里面创建Android.mk,Sum.cpp,以及将刚生成的.h文件复制到jni文件夹下,步骤如下:

这里写图片描述

Android.mk内容说明:
LOCAL_PATH := (callmydir)include(CLEAR_VARS)
LOCAL_MODULE :=JNISum //模块的名称,和之前的loadLibrary里面的名字对应,也是生成的.so文件的名字
LOCAL_SRC_FILES:=Sum.cpp //要参与编译的源文件,底层使用c++实现,对应的.cpp文件
include $(BUILD_SHARED_LIBRARY)

Sum.cpp内容说明:
在编辑.cpp文件文件时先把这个modle连接到gradle中,as面板选择File–>Link C++ Project with gradle–>build system选择ndk-build–>project path选择android.mk的路径,做了这一步的话那么在写cpp文件的时候函数就有了提示,错误的日志也会显示

jni与java类型对应表图1-1
规则:
1、类的签名:L+包名+类名+;的形式,比如Ljava/lang/String;代表String类的签名。
2、基本数据类型签名:如下表都以大写字母做签名,除了byte和long
3、对象的签名:对象所属的类的签名
4、数组的签名:[+类型的签名,比如:[i 代表int[]签名
5、多维数组的签名:n个[+类型签名,比如[[I代表int[][]签名。
6、方法签名:(参数类型签名)+返回值类型签名 (ID[I)Z代表 boolean fun1(int a,double b,int[] c)函数

JNI类型 JAVA类型 签名 jboolean boolean Z jbyte byte B jshort short S jchar char C jint int I jlong long J jfloat float F jdouble double D void void V jobject Object Ljava/lang/Object; jclass Class Ljava/lang/Class; jstring String Ljava/lang/String; jobjectArray Object[] [ Ljava/lang/Object; jbooleanArray boolean[] [Z jbyteArray byte[] [B jcharArray char[] [C jshortArray short[] [S jintArray int[] [I jlongArray long[] [J jfloatArray float[] [F jdoubleArray double[] [D jthrowable Throwable

这里写图片描述
//直接把.h里面的方法名给复制过来,然后该加的参数名自己加上,免得自己一个个的敲敲错了,这里的方法名是有含义的,返回值类型是int类型,jni与java类型对应表如图1-1,所以这里是jint,java_site_zhangyun_jnidemo_Sum_getSum意思是java_包名类名方法名,JNIEnv *表示一个指向JNI环境的指针,可通过它来访问JNI提供的接口方法,obj是java对象的this,JNICALL 和JNIEXPORT 是JNI中定义的宏

JNIEXPORT jint JNICALL Java_site_zhangyun_jnidemo_Sum_getSum(JNIEnv *env, jobject obj, jint x, jint y) {

//c++实现求和赋值给jint,直接return就实现了java调c++,这里还需实现c++调用java,所以不返回
jint sumresult = x + y;


//下面是C++调用静态的java方法jclass classs = env->FindClass("site/zhangyun/jnidemo/Sum");//括号的参数是包路径到类的路径if (classs == NULL) {    printf("find class Sum error !");    return sumresult;}//(II)I是getSub这个方法的签名,getSub是方法名,找到这个静态方法的id,getSub具体实现实在java实现的额jmethodID id = env->GetStaticMethodID(classs, "getSub", "(II)I");if (id == NULL) {    printf("find Method getSub error !");    return sumresult;}//调用这个静态的方法,传入clas,方法id,参数就完成了c++调用javajint subresult = env->CallStaticIntMethod(classs, id, x, y);

//下面是c++调用非静态的java方法jclass clazz = env->FindClass("site/zhangyun/jnidemo/Sum");if (clazz == NULL) {    printf("find class Sum error !");    return sumresult;}//找到Sum类的构造器,构造器使用的默认的构造器,方法名就是init,签名是()V代表Sum(){}方法jmethodID mid_construct = env->GetMethodID(classs, "<init>", "()V");if (mid_construct == NULL) {    printf("找不到默认的构造方法");    return sumresult;}//public int getMult(int x,int y)方法的签名是(II)I不懂得查看图1-1签名规则jmethodID mid_instance = env->GetMethodID(classs, "getMult", "(II)I");if (mid_instance == NULL) {    printf("find Method getMult error !");    return sumresult;}//创建Sum类的对象,非静态的方法必须用对象调用jobject jobj = env->NewObject(clazz,mid_construct);if (jobj == NULL) {    printf("创建对象失败!");    return sumresult;}// 5、调用对象的实例方法jint multresult=env->CallIntMethod(jobj, mid_instance, x, y);env->DeleteLocalRef(jobj);return sumresult + subresult+multresult;

}

第四步:要使用as编译so还需在build.gradle中写下配置信息
这里写图片描述

第5步:运行结果如下:
这里写图片描述
这里写图片描述

  • 第六步:demo下载地址为:http://download.csdn.net/detail/u013200864/9692429
1 0
原创粉丝点击