熟悉JNI开发:
JNI:java本地开发接口(Java Native Interface)
想要在java的应用程序里面调用C代码,就必须用到JNI
JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(c/c++)
通过这个协议,java代码就可以调用外部的c/c++代码,
外部的c/c++代码也可以调用java代码
为什么要用JNI:
JNI扩展了java虚拟机的能力
Native code(c代码) 效率高。在数学运算,实时渲染的游戏,音视频处理(极品飞车)。
为什么c比java高效???
暂时理解为java是夸平台的,要通过虚拟机和操作系统进行交互,
而c语言不是。
JNI开发流程:
1.创建一个android工程
2.JAVA代码中写声明native 方法 public native String helloFromJNI();
3.用javah工具生成头文件
4. 创建jni目录,引入头文件,根据头文件实现c代码
5.编写Android.mk文件
6.Ndk编译生成动态库
7.Java代码load 动态库.调用native代码
具体操作:
ndkpassdata工程:
1,在DataProvider.java中:(注意:这些方法都有一个修饰符native)
/**
* 把两个java中的int传递给c语言, c语言处理完毕后,把相加的结果返回给java
* @param x
* @param y
* @return
*/
public native int add(int x ,int y);
/**
* 把java中的string传递给c语言, c语言获取到java中的string之后 ,在string后面添加 一个hello 字符串
* @param s
* @return
*/
public native String sayHelloInC(String s);
/**
* 把java中的一个int数组 传递给c语言,c语言处理完毕这个java数组
* 把int数组中的每一个元素+10 ;
* 然后把结果返回给java
* @param iNum
* @return
*/
public native int[] intMethod(int[] iNum);
2,DemoActivity.java中:
private DataProvider provider;
onCreate()方法中:provider=new DataProvider();
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1:
int result = provider.add(3, 5);
Toast.makeText(this, "相加的结果"+result, 1).show();
break;
case R.id.bt2:
String str = provider.sayHelloInC("zhangsan ");
Toast.makeText(this, str, 1).show();
break;
case R.id.bt3:
int[] arr = {1,2,3,4,5};
provider.intMethod(arr);
for(int i=0;i<arr.length;i++){
System.out.println("java "+ arr[i]);
}
break;
}
3,利用javah生成头文件:
命令行进入当前工程目录:cd /d G:\android-JNI\ndkpassdata_LJ
然后进入bin目录:cd bin
进入classes目录 :cd classes (classes目录下面包含当前工程所有编译好的class文件)
然后生成头文件:javah cn.itcast.ndk3.DataProvider
这样在classes目录下面就会有一个.h的头文件。
4,在ndkpassdata工程下新建一个jni目录,把生成的头文件拷贝到该目录。
在jni目录下新建一个Android.mk,并编写mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=Hello
LOCAL_SRC_FILES :=Hello.c
LOCAL_LDLIBS += -llog //这一行的作用是为了在c代码中使用logcat
include $(BUILD_SHARED_LIBRARY)
5,编写在jni目录下新建Hello.c,并编写Hello.c
#include<stdio.h>
#include<jni.h>
#include "cn_itcast_ndk3_DataProvider.h";
#include <android/log.h>
#include<malloc.h>
#define LOG_TAG "System.out.c"
#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 jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
(JNIEnv * env, jobject obj , jint x, jint y){
LOGD("x=%d",x);
LOGD("y=%d",y);
return x+y;
}
JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC
(JNIEnv * env, jobject obj, jstring jstr ){
//在c语言中 是没有java的String
char* cstr = Jstring2CStr(env, jstr);
LOGD("cstr=%s",cstr);
// c语言中的字符串 都是以'/0' 作为结尾
char arr[7]= {' ','h','e','l','l','o','\0'};
strcat(cstr,arr);
LOGD("new cstr=%s",cstr);
return (*env)->NewStringUTF(env,cstr);
}
JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod
(JNIEnv * env , jobject obj , jintArray arr){
//1.知道数组的长度
//2.操作这个数组里面的每一个元素
int len = (*env)->GetArrayLength(env,arr);
LOGD("shuzu len =%d",len);
jint* intarr = (*env)->GetIntArrayElements(env,arr,1);
int i =0; //c99
for(;i<len;i++){
//*(intarr+i) += 10;
LOGD("intarr[%d]=%d", i, intarr[i]);
intarr[i]+= 10;
}
return arr;
}
6,NDK编译生成动态库:
打开Cygwin这个程序,
1,cd cygdrive
2,cd g (进入G盘)
3,cd android-JNI
4,cd ndkpassdata_LJ
5,ndk-build (把c代码编译成.so的可执行的二进制文件)
这样在ndkpassdata_LJ/libs/armeabi就生成了一个libHello.so文件
7,java代码load动态库,并调用native方法:
DemoActivity.java中:
static{
System.loadLibrary("Hello");
//注意这里的Hello和mk文件中的LOCAL_MODULE :=Hello
//还有libHello.so是对应的。。
}