JNI

JNI,称为Java本地接口。它是翻译Java和C之间的中间件。
使用JNI的好处:

①可以进行驱动开发。
Java代码运行在虚拟机上,无法直接和操作系统交互,而C代码可以做驱动开发,就可以利用Java调C的方式来进行驱动开发。
②可以使用很多用C代码写好的函数库。(C代码年代久远,有很多可以复用的函数库)
③C代码运算效率高,调用C代码可以提高效率。

一,JNI开发的第一步,回顾下C语言

C和Java基本数据类型的对比:
这里写图片描述
可以通过sizeof来获得数据类型的长度。
类型的修饰符,对长度没有影响,对值的范围的有影响 。

signed    有符号位     第一位是符号位  
unsigned  无符号位     第一位不是符号位   所有的数全部是正数
void      不确定长度   空 
C语言常用的格式化符号:
            %d      带符号的十进制数
            %c      单个字符
            %s      字符串
            %f      6位小数
            %x      16进制数
            %#x     有0x的16进制数
C语言的指针:

int i=3;
int* j=&i;
*j=4;

&i,表示i这个变量在内存中的地址。
int*,表示的是存放内存地址的变量,也称为指针变量或指针。
*j,表示的是指针的运算符,可以找到j指针变量存放的内存地址所对应的值。

交换两个数,如果想要修改主函数变量的值,必须把变量的指针传递到子函数中。
C语言的数组:
①数组中的元素在一块连续的内存空间中
②数组中的变量名的值,就是第一个元素的内存地址。

void printArray(int* array,int len){
    int i;//不能在for循环里声明变量 
    for(i=0;i<len;i++){
         //指针可以自动识别要移动多少偏移,不用担心i的值。
         printf("数组的第%d个元素为%d\n",i,*(array+i)); 
    } 
}

main(){
    int array[]={1,2,3};
    printArray2(array,3);//array数组中的第一个元素的内存地址
      system("pause");  
} 
C语言的内存结构:
分为栈内存和堆内存。

栈内存:
栈内存从上到下分为
    .data区      常量加载.data.code区      方法加载在.code区
    栈内存

栈内存是连续的内存空间,它是系统自动分配的内存,可以自动回收,效率很高。但是大小是有限制的。

堆内存:
程序员手动去申请的内存在堆内存,在堆内存开辟空间,不会限制大小
(大小的上限取决于堆内存的剩余大小),但是堆内存中容易产生碎片。
会导致效率慢,需要程序员手动回收。
结构体和联合体:

结构体用于封装对象
//声明了一个结构体  
struct Student
{
    int age;  
    float score; 
    char sex;  
    double d;           
};

联合体里的元素共享一块内存
//声明联合体
union mix
{ 
 long i; 
 int k; 
 char ii; 
} ;

二,NDK
NDK,本地的开发工具包。

NDK的作用,交叉编译,具体可以:

①把C语言写好的代码打包生成可以在手机上(linux平台)可以运行的文件。
②把C语言的函数库(.dll)打包生成手机下的(.so)文件。

JNI的协议规范:

找到NDK的安装目录下的
android-ndk-r9b\platforms\android-9\arch-arm\usr\include的jni.h文件。

jni.h开头有这么一段:

#ifdef HAVE_INTTYPES_H
typedef uint8_t         jboolean;       /* unsigned 8 bits */
typedef int8_t          jbyte;          /* signed 8 bits */
typedef uint16_t        jchar;          /* unsigned 16 bits */
typedef int16_t         jshort;         /* signed 16 bits */
typedef int32_t         jint;           /* signed 32 bits */
typedef int64_t         jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */
#else
typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */

如果HAVE_INTTYPES_H已经被define定义过,那么就为ifdef下的语句,否则执行else下的语句。
这些以"j"开头的别名,表示的是在java类型在jni中的别名。

typedef const struct JNINativeInterface* JNIEnv;
JNIEnv是JNINativeInterface结构体指针的别名。
而结构体JNINativeInterface中有很多可以使用的方法。

在android studio进行JNI的开发过程:

①在Activity中写一个native方法,native方法类似于抽象方法,会在C代码中去实现。

public native String helloFromeC();

//引入库
static{
        System.loadLibrary("helloJni");
}
②利用javah命令生成.h头文件。生成头文件的原因是,在C代码中要写出能够匹配java方法的方法名实在费劲而且会很容易出错。而头文件里可以直接生成方法。

在cmd窗口,找到native方法对应的java文件。(由于我使用的是JDK1.7以上的JDK),进入到src/main/包名下,找到指定mActivity.java。

-classpath 要指定路径是包所在的根路径。

javah -classpath 包名.mActivity
③在module下的build.gradle的defaultConfig声明.so库的名称
ndk{
   moduleName "helloJni"//指定库的名称
}
在local.properties中声明NDK的路径(指定NDK路径会自动添加)
ndk.dir=D\:\\sdk\\ndk-bundle
④创建jni目录,创建c代码,去写native方法的实现。

#include <jni.h>
#include <android/log.h>//引入log.h

//在C代码中使用LOG
#define LOG_TAG "====>"
//写一个宏定义的方法,把复杂的方法转换为简单的表示的方法
//ANDROID_LOG_DEBUG和ANDROID_LOG_INFO表示Log的类型,LOG_TAG表示过滤的条件,__VA_ARGS__表示不固定的参数
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__);

JNIEXPORT jstring JNICALL Java_asule_myjniandndk_MainActivity_helloFromeC(JNIEnv* env, jobject obj){
    LOGD("ronaldo");
    LOGI("hehe");
    return (*env)->NewStringUTF(env,"hello");
}
那么现在一个简单的JNI开发过程就完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值