JNI_1


什麼是JNIhtml

JNI(Java Native Interface) java本地開發接口 
JNI
是一個協議, 有了這個協議可使Java代碼和C/C++代碼相互調用.java

爲何用JNIandroid

1、擴展JVM功能,訪問驅動,操做硬件(物聯網、智能家居、 
車載電腦) 
2
、效率上c/c++語言效率更高數學運算,實時渲染的遊戲上, 
視頻處理 
3
java反編譯比c語言容易, 經過JNI加強代碼安全性(加密算法放到C實現)c++

4、代碼移植,複用已經存在的c代碼(opencv,ffmpeg…程序員

怎麼用JNI算法

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

開發環境介紹編程

windows下用輕量級 dev-c++windows

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);

本站公眾號
   歡迎關注本站公眾號,獲取更多信息