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

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类型签名
jbooleanbooleanZ
jbytebyteB
jshortshortS
jcharcharC
jintintI
jlonglongJ
jfloatfloatF
jdoubledoubleD
voidvoidV
jobjectObjectLjava/lang/Object;
jclassClassLjava/lang/Class;
jstringStringLjava/lang/String;
jobjectArrayObject[][ Ljava/lang/Object;
jbooleanArrayboolean[][Z
jbyteArraybyte[][B
jcharArraychar[][C
jshortArrayshort[][S
jintArrayint[][I
jlongArraylong[][J
jfloatArrayfloat[][F
jdoubleArraydouble[][D
jthrowableThrowable

这里写图片描述
//直接把.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++调用java
jint 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步:运行结果如下:
这里写图片描述
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值