首先说明下相应的概念:
NDK是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。它集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。它可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
简言之:NDK是一种工具。借助他可以实现一些更适合Android平台版本的C/C++开发
起始:NDK是Google公司推出的帮助Android开发者通过C/C++本地语言编写应用的开发包
JNI是java语言提供的Java和C/C++相互沟通的机制,Java可以通过JNI调用本地的C/C++代码,本地的C/C++的代码也可以调用java代码。JNI 是本地编程接口,Java和C/C++互相通过的接口。Java通过C/C++使用本地的代码的一个关键性原因在于C/C++代码的高效性。
简言之:JNI是一些头文件,里面定义了一些方法以及使用标准
起始:JNI是Java调用Native机制,是Java语言自己的特性全称为Java Native Interface
总之:NDK是一种工具需要借助JNI的标准。所以他们扯在了一起,这里有篇不错的文章:NDK与JNI的关系
JNI的一些数据类型:

在Android最新的NDK与JNI开发中,以前的.mk文件被替换为了CMakeList.txt
创建一个NDK工程并实现属性引用
首先你得去下一堆东西,补充相应的环境支持 也就是Android Studio 中要安装 Android SDK->SDK Tools中安装 CMake, LLDB, NDK. 很大,时间炒鸡久,特别是还被墙(2-3M的速度大概用了30分钟?不太记得清)

另外检查一个插件是否勾上

安装完新建工程时勾选Include C++ support,然后在工程的Project 工具栏选择,Project选项 ,你会发现多了几个文件,在main中和java对齐的cpp目录里包括了一个.cpp的实现,src目录同级多了一个CMakeList.txt
实际上AS已经生成了一些示例,有没有似曾相识?


毋庸置疑,运行后肯定就是显示Hello from C++了,写这里的代码你不喜欢用->的话可以用.(点)然后按Table键IDE很舒服的帮你转换方法调用,仿写一个方法

使用IDE的提示去自动在CPP里创建方法,然后会发现,这个套路原来是一样的

这样我们就知道自己怎么去创建了,那个extern “C”是代表支持混合编程的意思,下面我们改下
extern "C"
JNIEXPORT jstring JNICALL
Java_com_lckiss_ndkgradle_MainActivity_updateNameFromC(JNIEnv *env, jobject instance) {
// Jobject代表的是谁调用的这个方法,比如这里就是MainActivity的类对象 首先混去jclass
//C++的命名习惯性加_
jclass _jclass=env->GetObjectClass(instance);
/**
* 获取属性ID jfieldID GetFieldID(jclass clazz, const char* name, con st char* sig)
* 第二个参数表示我们想要获取的属性名 比如我们新加的name,
* 第三个参数看下面的图,其代表的是JNI想要访问Java中的属性,变量等需要的一个签名
* String不属于基本数据类型 所以需要用简写加上类的完整路径就是L java/lang/String ;
*/ jfieldID _jfieldID = env->GetFieldID(_jclass,"name","Ljava/lang/String;");
/**
* jobject GetObjectField(jobject obj, jfieldID fieldID)
* object向下强转为jstring 和java一样
*/ jstring res= (jstring) env->GetObjectField(instance, _jfieldID);
//输出下
printf("%#x\n",res);
//转换成Java的string去调用
char * str= (char *) env->GetStringUTFChars(res, NULL);
//新生成一个char数组去拼接,方便演示
char text[20]="success";
char* finalRes= strcat(str,text);
//最后将结果返回
return env->NewStringUTF(finalRes);
}然后MainActivity中:
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
//新定义一个属性
public String name="Test ";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(updateNameFromC());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/ public native String stringFromJNI();
public native String updateNameFromC();
}运行下就会显示test success。
test success
其实简单的用法就是这样,并没什么难度,NDK已经简化了很多很多东西,附上签名描述图

JNI常用方法函数

JIN方法数组的引用(静态方法等等诸如此类)
继续在Activity中添加方法
public String getName(){
return "this is name form act";
}
//我们来通过这个方法来返回上面的 "this is name form act"
public native String getMethod();然后按老套路继续写Cpp,顺便改Activity中的那个textview.setText的来源
extern "C"
JNIEXPORT jstring JNICALL
Java_com_lckiss_ndkgradle_MainActivity_getMethod(JNIEnv *env, jobject instance) {
//先拿到class
jclass _jclass = env->GetObjectClass(instance);
//拿方法 jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
jmethodID _jmethodID = env->GetMethodID(_jclass, "getName", "()Ljava/lang/String;");
//jni调用java的方法 静态方法等诸如此类 env->CallStaticObjectMethod()
jstring _jstring = (jstring) env->CallObjectMethod(instance, _jmethodID);
//转换成Java的string去调用 和上面一样
char *str = (char *) env->GetStringUTFChars(_jstring, NULL);
//新生成一个char数组去拼接,方便演示
char text[20] = "success";
char *finalRes = strcat(str, text);
//最后将结果返回
return env->NewStringUTF(finalRes);
}最后肯定是返回:
this is name form act success
附上方法的签名图

小彩蛋:
so库文件哪里找?

还有SDK目录下NDK的一些东西

接下来是数组的引用
Activity中加入以下内容
private int[] source={1,4,0,7,33,11};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(getMethod());
//利用JNI来进行数组排序
getArray(source);
for (int i = 0; i <source.length ; i++) {
Log.d("source", "onCreate: "+source[i]);
}
}
public native void getArray(int[] arrays);Cpp中追加头文件以及内容
#include <stdlib.h>
/**
* 首先将__lhs强制声明为指向整数的指针(int*),再读取指针对应的整数(最外面的*)
* @param __lhs
* @param __rhs
* @return
*/int compare(const void* __lhs, const void* __rhs){
return (*(int*)__lhs-*(int*)__rhs);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_lckiss_ndkgradle_MainActivity_getArray(JNIEnv *env, jobject instance, jintArray arrays_) {
//已经自动拿到了数组
jint *arrays = env->GetIntArrayElements(arrays_, NULL);
//获取数组长度
int _len= env->GetArrayLength(arrays_);
//void qsort(void* __base, size_t __nmemb, size_t __size, int (*__comparator)(const void* __lhs, const void* __rhs));
//第三个参数是需要实现的一个方法
qsort(arrays,_len, sizeof(int),compare);
env->ReleaseIntArrayElements(arrays_, arrays, 0);
}然后运行,你会发现排序成功,

基本上就是这样子玩了,套路都是一样一样的。秒秒钟就成了老司机
第一部分完结,请看第二部分:NDK与JNI基础-JIN的引用、缓存策略、异常
本站广告由 Google AdSense 提供
0条评论