JNI_1


什么是JNI

JNI(Java Native Interface) java本地开发接口 
JNI
是一个协议, 有了这个协议可以使Java代码和C/C++代码相互调用.

为什么用JNI

1、扩展JVM功能,访问驱动,操作硬件(物联网、智能家居、 
车载电脑) 
2
、效率上c/c++语言效率更高数学运算,实时渲染的游戏上, 
视频处理 
3
java反编译比c语言容易, 通过JNI增强代码安全性(加密算法放到C实现)

4、代码移植,复用已经存在的c代码(opencv,ffmpeg…

怎么用JNI

1.C/C++语言 
2.
掌握java jni流程 
3.NDK (native develop kits )

开发环境介绍

windows下用轻量级 dev-c++

C语言基本数据类型

Java 八大基本数据类型 C基本数据类型

boolean 
byte 
char char 
int int 
float float 
double double 
long long 
short short 
C
没有boolean byte 
signed unsigned
有符号无符号修饰符只能修饰整形变量 
signed
有符号最高位符号位可以表示负数 
unsigned
无符号最高位仍然是数值位不可以表示负数

输入输出函数

输出函数 
printf(“
要输出的内容+占位符”,…….) 
常用占位符 
%d - int 
%ld – long int 
%lld - long long 
%hd –
短整型 
%c - char 
%f - float 
%lf – double 
%u –
无符号数 
%x –
十六进制输出 int 或者long int 或者short int 
%o -
八进制输出 
%s –
字符串

输入函数 Scanf 

Int len; 
Scanf(“%d”,&len); &取地址符号

 

 

什么是指针

int main(void)
{
    int * p; //p 是变量的名字, int * 是一个类型
    //这个变量存放的是int类型变量的地址。
    int i =3;
    p=&i;
    system(“pause”);
      return 0;
}

 

指针常见错误

指针变量声明后未赋值直接用

声明的指针类型和指向的类型要一致

指针和指针变量的关系

指针就是地址,地址就是指针 
地址就是内存单元的编号 
指针变量是存放地址的变量 
指针和指针变量是两个不同的概念 
但是要注意:通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样

为什么使用指针

直接访问硬件 (opengl 显卡绘图
快速传递数据(指针表示地址
返回一个以上的值(返回一个数组或者结构体的指针
表示复杂的数据结构(结构体
方便处理字符串

*号的三种含义

*号的含义 
数学运算符: 3 * 5 
定义指针变量: int * p 
指针运算符(取值): *p (p的内容(地址)在内存中的值)

指针练习互换两个数字

swap(int* i, int* j) { // 引用传递
     int temp = *i;
       *i = *j;
       *j = temp; 
}

main() 
       int i = 89;
       int j = 10;
      swap(&i, &j);
      printf("i=%d\n", i);
       printf("j=%d\n", j);
      system("pause");
}

 

指针练习函数返回一个以上的值

change(int* a, int* b) {
    *a = 1;
    *b = 2;
}

main() {
    int a = 3, b = 5;
    change(&a, &b);
    printf(“a=%d, b=%d\n”, a, b);
    system(“pause”);
}

 

指针和数组的关系

数组名 
int a[5]; // a
是数组名,5是数组的大小,元素个数 
数组名称是个指针常量,它存放的是数组中第一个元素的地址 
int a[5]; 
&a[0]
等价于 &a 
下标和指针的关系 
int a[5]; 
a[i]
等价于 *(a + i) // 这里i的范围是0~4(数组长度 -1)

指针的长度

不管什么类型的指针都是4个字节.(64位系统8字节
C
语言为了方便指针运算, 定义各种基本类型的指针, 每种类型的指针运算时所偏移量的值是根据类型的长度决定的.

多级指针

int i = 10; 
int* p1 = &i; // 一级指针 
int** p2 = &p1; // 二级指针 
int*** p3 = &p2; // 三级指针 
int**** p4 = &p3; // 四级指针 
****p4 = 99; // 修改变量i的值为99;

 

主函数获取子函数变量地址

void function(int** p){
     int i = 4;
     *p = &i;
     printf("子函数打印i的地址为%#x\n", &i);    
}

main(){
       int* mainp;
       function(&mainp);      
       printf("主函数打印i的地址为%#x\n", mainp);    
       printf("i的值为%d\n", *mainp);
       system("pause");
}

 

静态内存和动态内存

静态内存是系统是程序编译执行后系统自动分配,由系统自动释放, 静态内存是栈分配的
动态内存是开发者手动分配的, 是堆分配的
栈内存 
*
系统自动分配 
*
系统自动销毁 
*
连续的内存区域 
*
向低地址扩展 
*
大小固定 
*
栈上分配的内存称为静态内存 
堆内存 
*
程序员手动分配 
* java
new * cmalloc 
*
空间不连续 
*
大小取决于系统的虚拟内存 
* C
:程序员手动回收free 
* java
:自动回收 
*
堆上分配的内存称为动态内存

申请堆内存

malloc(memory allocate) 函数 
malloc
申请一块堆内存

free(地址); 回收内存 
回收malloc 申请的堆内存

realloc re- allocate 
重新申请一块堆内存

结构体

struct Student {
    int age;
    float score;
    char sex;
};

 
main() {
    struct Student stu = {18, 88.5, 'M'};
}

 

使用结构体变量

struct Student stu = {80,55.5,'F'};
struct Student stu2;
stu2.age = 10;
stu2.score = 88.8f;
stu2.sex= ‘M';


printf("%d %f %c\n", st.age, st.score, st.sex); 
// 结构体指针
struct Student * pStu;
pStu = &stu;
pStu->age 在计算机内部会被转换为 (* pStu).age

 

 

pStu ->age的含义: pStu所指向的结构体变量中的age这个成员

函数的指针

1.定义int (*pf)(int x, int y); 
2.
赋值 pf = add; 
3.
引用 pf(3,5); 
4.
结构体中不能定义函数,只能声明函数指针

Union 联合体

struct Date {
      int year;
      int month;
     int day;
};

union Mix {
     long i;
     int k;
     char ii;
};

main() {
       printf("date:%d\n",sizeof(struct Date));
       printf("mix:%d\n",sizeof(union Mix));
       system("pause");
}

 

枚举

enum WeekDay {
     Monday=0,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};

 

main() {
       enum WeekDay day = Sunday;
       printf("%d\n",day);
       system("pause");
}

 

typedef

声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。

#include <stdio.h>
#include <stdlib.h>
typedef int i;
typedef long l;
main() {
       i m = 10;
       l n = 123123123;
       printf("%d\n", m);
       printf("%ld\n", n);
       system("pause");      
}

 

JNI 协议

 

NDK HelloWorld

1.创建一个android工程 
2.java
代码中写声明native方法 
3.
创建jni目录,编写c代码,方法名字要对应 
4.
编写Android.mk文件 
5.NDK
编译生成动态链接库 
6.java
代码load动态库.调用native代码

javah 生成头文件

注意: 不同版本的JDK操作方式不同.

命令: javah <包名+类名>

JDK1.6使用方式 
在工程的bin/classes目录下, 执行javah命令
JDK1.7
使用方式 
在工程的src目录下, 执行javah命令.

NDK 简便开发流程

1.     关联NDK: Window -> Preferences -> Android -> NDK

2.     创建Android工程, 声明native方法.

3.     设置函数库名字: 右键工程 -> Android Tools -> App Native support

4.     使用javah生成.h的头文件, 并把.h文件拷贝到工程下jni文件夹中.

5.     c代码提示: 右键工程 -> Properties -> C/C++ General -> Path and Symbols // Includes -> Add -> File system 选中以下路径.latforms\android-18\arch-arm\usr\include

6.     把后缀名.cpp改成.c, 实现native方法.

7.     java代码中加载动态库, 调用native方法.

java c之间的数据传递

public native int add(int x, int y); 
public native String sayHelloInC(String s); 
public native int[] arrElementsIncrease(int[] intArray);

c代码中使用logcat

Android.mk文件增加以下内容

LOCAL_LDLIBS += -llog

C代码中增加以下内容

#include <android/log.h
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
C代码中使用logcat, 例:
LOGI("info\n");
LOGD("debug\n");

 

C语言调用java方法

C调用java空方法 
public void helloFromJava(){ 

C
调用java中的带两个int参数的方法 
public int add(int x,int y) { 

C
调用java中参数为string的方法 
public void printString(String s){ 
}

JNI 方法签名

签名类型 Java类型 
Z boolean 
B byte 
C char 
S short 
I int 
J long 
F float 
D double 
L
全类名; 引用类型 
[
类型数组

C语言回调java静态方法

C语言调用下面静态方法.

    

public static void sayHello(String text) {
        System.out.println("MainActivity:showText: " + text);
    }

 

 

C语言回调java刷新界面

C语言调用下面Activity中方法, 弹出吐司.

    public void showToast(String text) {
        Toast.makeText(this, text, 0).show();
    }

 

 

eclipse找不到ndk选项解决办法

NDK插件 com.android.ide.eclipse.ndk_23.0.2.1259578.jar 如果在eclipse里配置ndk却发现没有配置的选项,则需要此插件,放置在eclipse/plugins下,重启即可。

AM命令

am命令 :adb shell里可以通过am命令进行一些操作如启动activity Service 启动浏览器等等 
am
命令的源码在Am.java, adb shell里执行am命令实际上就是启动一个线程执Am.javamain方法,am命令后面带的参数都会当作运行时的参数传递到main函数中 
am
命令可以用start子命令,并且带指定的参数 
常见参数: -a: action -d data -t 表示传入的类型 -n 指定的组件名字 
举例: adb shell中通过am命令打开网页 
am start –user 0 -a android.intent.action.VIEW -d 
http://www.baidu.com 
通过am命令打开activity 
am start –user 0 -n com.ngyb.cpphello/com.ngyb.cpphello.MainActivity

execlp

execlp c语言中执行系统命令的函数 
execlp()
会从PATH环境变量所指的目录中查找符合参数file的文件找到后就执行该文件, 第二个参数开始就是执行这个文件的 args[0],args[1] 最后一个参数用(char*)NULL结束 
android
开发中 execlp函数对应androidpath路径为 
system/bin/
目录 
调用格式 
execlp(“am”, “am”, “start”, “–user”,”0”,”-a”, “android.intent.action.VIEW”, “-d”, “
http://www.baidu.com“, (char *) NULL);

execlp(“am”, “am”, “start”, “–user”,”0”, “-n” , “com.ngyb.cforktest/com.ngyb.cforktest.MainActivity”,(char *) NULL);

 

 


什么是JNI

JNI(Java Native Interface) java本地开发接口 
JNI
是一个协议, 有了这个协议可以使Java代码和C/C++代码相互调用.

为什么用JNI

1、扩展JVM功能,访问驱动,操作硬件(物联网、智能家居、 
车载电脑) 
2
、效率上c/c++语言效率更高数学运算,实时渲染的游戏上, 
视频处理 
3
java反编译比c语言容易, 通过JNI增强代码安全性(加密算法放到C实现)

4、代码移植,复用已经存在的c代码(opencv,ffmpeg…

怎么用JNI

1.C/C++语言 
2.
掌握java jni流程 
3.NDK (native develop kits )

开发环境介绍

windows下用轻量级 dev-c++

C语言基本数据类型

Java 八大基本数据类型 C基本数据类型

boolean 
byte 
char char 
int int 
float float 
double double 
long long 
short short 
C
没有boolean byte 
signed unsigned
有符号无符号修饰符只能修饰整形变量 
signed
有符号最高位符号位可以表示负数 
unsigned
无符号最高位仍然是数值位不可以表示负数

输入输出函数

输出函数 
printf(“
要输出的内容+占位符”,…….) 
常用占位符 
%d - int 
%ld – long int 
%lld - long long 
%hd –
短整型 
%c - char 
%f - float 
%lf – double 
%u –
无符号数 
%x –
十六进制输出 int 或者long int 或者short int 
%o -
八进制输出 
%s –
字符串

输入函数 Scanf 
Int len; 
Scanf(“%d”,&len); &
取地址符号

什么是指针

int main(void)

{

    int * p; //p 是变量的名字, int * 是一个类型

    //这个变量存放的是int类型变量的地址。

    int i =3;

    p=&i;

    system(“pause”);

      return 0;

}

指针常见错误

指针变量声明后未赋值直接用

声明的指针类型和指向的类型要一致

指针和指针变量的关系

指针就是地址,地址就是指针 
地址就是内存单元的编号 
指针变量是存放地址的变量 
指针和指针变量是两个不同的概念 
但是要注意:通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样

为什么使用指针

直接访问硬件 (opengl 显卡绘图
快速传递数据(指针表示地址
返回一个以上的值(返回一个数组或者结构体的指针
表示复杂的数据结构(结构体
方便处理字符串

*号的三种含义

*号的含义 
数学运算符: 3 * 5 
定义指针变量: int * p 
指针运算符(取值): *p (p的内容(地址)在内存中的值)

指针练习互换两个数字

swap(int* i, int* j) { // 引用传递

     int temp = *i;

       *i = *j;

       *j = temp; 

}

 

main() {

       int i = 89;

       int j = 10;

      swap(&i, &j);

      printf("i=%d\n", i);

       printf("j=%d\n", j);

      system("pause");

}

指针练习函数返回一个以上的值

change(int* a, int* b) {

    *a = 1;

    *b = 2;

}

 

main() {

    int a = 3, b = 5;

    change(&a, &b);

    printf(“a=%d, b=%d\n”, a, b);

    system(“pause”);

}

指针和数组的关系

数组名 
int a[5]; // a
是数组名,5是数组的大小,元素个数 
数组名称是个指针常量,它存放的是数组中第一个元素的地址 
int a[5]; 
&a[0]
等价于 &a 
下标和指针的关系 
int a[5]; 
a[i]
等价于 *(a + i) // 这里i的范围是0~4(数组长度 -1)

指针的长度

不管什么类型的指针都是4个字节.(64位系统8字节
C
语言为了方便指针运算, 定义各种基本类型的指针, 每种类型的指针运算时所偏移量的值是根据类型的长度决定的.

多级指针

int i = 10; 
int* p1 = &i; //
一级指针 
int** p2 = &p1; //
二级指针 
int*** p3 = &p2; //
三级指针 
int**** p4 = &p3; //
四级指针 
****p4 = 99; //
修改变量i的值为99;

主函数获取子函数变量地址

void function(int** p){

     int i = 4;

     *p = &i;

     printf("子函数打印i的地址为%#x\n", &i);    

}

main(){

       int* mainp;

       function(&mainp);      

       printf("主函数打印i的地址为%#x\n", mainp);    

       printf("i的值为%d\n", *mainp);

       system("pause");

 

}

静态内存和动态内存

静态内存是系统是程序编译执行后系统自动分配,由系统自动释放, 静态内存是栈分配的
动态内存是开发者手动分配的, 是堆分配的
栈内存 
*
系统自动分配 
*
系统自动销毁 
*
连续的内存区域 
*
向低地址扩展 
*
大小固定 
*
栈上分配的内存称为静态内存 
堆内存 
*
程序员手动分配 
* java
new * cmalloc 
*
空间不连续 
*
大小取决于系统的虚拟内存 
* C
:程序员手动回收free 
* java
:自动回收 
*
堆上分配的内存称为动态内存

申请堆内存

malloc(memory allocate) 函数 
malloc
申请一块堆内存

free(地址); 回收内存 
回收malloc 申请的堆内存

realloc re- allocate 
重新申请一块堆内存

结构体

struct Student {

    int age;

    float score;

    char sex;

};

 

main() {

    struct Student stu = {18, 88.5, 'M'};

}

使用结构体变量

struct Student stu = {80,55.5,'F'};

struct Student stu2;

stu2.age = 10;

stu2.score = 88.8f;

stu2.sex= ‘M';

 

printf("%d %f %c\n", st.age, st.score, st.sex);

 

// 结构体指针

struct Student * pStu;

pStu = &stu;

pStu->age 在计算机内部会被转换为 (* pStu).age

 

pStu ->age的含义: pStu所指向的结构体变量中的age这个成员

函数的指针

1.定义int (*pf)(int x, int y); 
2.
赋值 pf = add; 
3.
引用 pf(3,5); 
4.
结构体中不能定义函数,只能声明函数指针

Union 联合体

struct Date {

      int year;

      int month;

      int day;

};

union Mix {

     long i;

     int k;

     char ii;

};

main() {

       printf("date:%d\n",sizeof(struct Date));

       printf("mix:%d\n",sizeof(union Mix));

       system("pause");

}

枚举

enum WeekDay {

     Monday=0,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday

};

 

main() {

       enum WeekDay day = Sunday;

       printf("%d\n",day);

       system("pause");

}

typedef

声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。

#include <stdio.h>

#include <stdlib.h>

typedef int i;

typedef long l;

main() {

       i m = 10;

       l n = 123123123;

       printf("%d\n", m);

       printf("%ld\n", n);

       system("pause");      

}

JNI 协议

NDK HelloWorld

1.创建一个android工程 
2.java
代码中写声明native方法 
3.
创建jni目录,编写c代码,方法名字要对应 
4.
编写Android.mk文件 
5.NDK
编译生成动态链接库 
6.java
代码load动态库.调用native代码

javah 生成头文件

注意: 不同版本的JDK操作方式不同.

命令: javah <包名+类名>

JDK1.6使用方式 
在工程的bin/classes目录下, 执行javah命令
JDK1.7
使用方式 
在工程的src目录下, 执行javah命令.

NDK 简便开发流程

1.     关联NDK: Window -> Preferences -> Android -> NDK

2.     创建Android工程, 声明native方法.

3.     设置函数库名字: 右键工程 -> Android Tools -> App Native support

4.     使用javah生成.h的头文件, 并把.h文件拷贝到工程下jni文件夹中.

5.     c代码提示: 右键工程 -> Properties -> C/C++ General -> Path and Symbols // Includes -> Add -> File system 选中以下路径.latforms\android-18\arch-arm\usr\include

6.     把后缀名.cpp改成.c, 实现native方法.

7.     java代码中加载动态库, 调用native方法.

java c之间的数据传递

public native int add(int x, int y); 
public native String sayHelloInC(String s); 
public native int[] arrElementsIncrease(int[] intArray);

c代码中使用logcat

Android.mk文件增加以下内容

LOCAL_LDLIBS += -llog

C代码中增加以下内容

#include <android/log.h>

#define LOG_TAG "System.out"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

C代码中使用logcat, :

LOGI("info\n");

LOGD("debug\n");

C语言调用java方法

C调用java空方法 
public void helloFromJava(){ 

C
调用java中的带两个int参数的方法 
public int add(int x,int y) { 

C
调用java中参数为string的方法 
public void printString(String s){ 
}

JNI 方法签名

签名类型 Java类型 
Z boolean 
B byte 
C char 
S short 
I int 
J long 
F float 
D double 
L
全类名; 引用类型 
[
类型数组

C语言回调java静态方法

C语言调用下面静态方法.

    public static void sayHello(String text) {

        System.out.println("MainActivity:showText: " + text);

    }

 

C语言回调java刷新界面

C语言调用下面Activity中方法, 弹出吐司.

    public void showToast(String text) {

        Toast.makeText(this, text, 0).show();

    }

 

eclipse找不到ndk选项解决办法

NDK插件 com.android.ide.eclipse.ndk_23.0.2.1259578.jar 如果在eclipse里配置ndk却发现没有配置的选项,则需要此插件,放置在eclipse/plugins下,重启即可。

AM命令

am命令 :adb shell里可以通过am命令进行一些操作如启动activity Service 启动浏览器等等 
am
命令的源码在Am.java, adb shell里执行am命令实际上就是启动一个线程执Am.javamain方法,am命令后面带的参数都会当作运行时的参数传递到main函数中 
am
命令可以用start子命令,并且带指定的参数 
常见参数: -a: action -d data -t 表示传入的类型 -n 指定的组件名字 
举例: adb shell中通过am命令打开网页 
am start –user 0 -a android.intent.action.VIEW -d 
http://www.baidu.com 
通过am命令打开activity 
am start –user 0 -n com.ngyb.cpphello/com.ngyb.cpphello.MainActivity

execlp

execlp c语言中执行系统命令的函数 
execlp()
会从PATH环境变量所指的目录中查找符合参数file的文件找到后就执行该文件, 第二个参数开始就是执行这个文件的 args[0],args[1] 最后一个参数用(char*)NULL结束 
android
开发中 execlp函数对应androidpath路径为 
system/bin/
目录 
调用格式 
execlp(“am”, “am”, “start”, “–user”,”0”,”-a”, “android.intent.action.VIEW”, “-d”, “
http://www.baidu.com“, (char *) NULL);

execlp(“am”, “am”, “start”, “–user”,”0”, “-n” , “com.ngyb.cforktest/com.ngyb.cforktest.MainActivity”,(char *) NULL);

 

 

转载于:https://www.cnblogs.com/nangongyibin/p/10465078.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值