最近乘着找工作闲余时间又温故了一遍android中的JNI何NDK的使用,一方面是为了巩固一下基础以防面试会问到,一方面是丰富一下博客内容,言归正传。
了解android中NDK的使用之前首先要知道JNI和NDK到底有什么关系,这是很多初学者的疑惑,我开始接触的时候也有过类似的疑问。如下解释(网络拷贝过来):
对于JNI和NDK很多Android开发初学者没有搞明白这个问题,JNI是Java调用Native机制,是Java语言自己的特性全称为Java Native Interface,类似的还有微软.Net Framework上的p/invoke,可以让C#或Visual Basic.Net可以调用C/C++的API,所以说JNI和Android没有关系,在PC上开发Java的应用,如果运行在Windows平台使用JNI是是经常的,比如说读写Windows的注册表。
而NDK是Google公司推出的帮助Android开发者通过C/C++本地语言编写应用的开发包,包含了C/C++的头文件、库文件、说明文档和示例代码,我们可以理解为Windows Platform SDK一样,是纯C/C++编写的,但是Android并不支持纯C/C++编写的应用,同时NDK提供的库和函数功能很有限,仅仅处理些算法效率敏感的问题,所以Android123推荐初学者学好Java后再学习JNI。
说白了,JNI是JAVA特有的东西,是为了提升JAVA语言的性能,C/C++效率肯定比JAVA的高,JNI的作用就是将一些耗时耗内存的工作交给C/C++来做,然后通过JNI来调用,因为JAVA不能直接使用外部语言。本地方法的声明,实现以及调用接下来会一一介绍。
在PC端例如在windows中,通过VC等编译器可以将生成的本地方法(也就是.c文件)生成动态链接库(.dll),而在android中(基于Linux的系统)会生成.so文件,而NDK就起到了类似如VC编译器的作用,为了方面开发者将所编写的.c文件打包成.so文件之用。
下面写个小例子方面理解Android中JNI和NDK的使用。
首先在eclipse中新建工程JNI_1,如下:
1、MainActivity.java如下:
package com.ldw.jni; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { private static String libName = "Hello"; static { System.loadLibrary(libName); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void startJNI(View v) { Toast.makeText(getApplicationContext(), getStringFromJNI(), Toast.LENGTH_SHORT).show(); } public native String getStringFromJNI(); }
这里有个地方要注意下,生成的so文件NDK默认会在前面加上lib,loadLibrary的时候注意库文件的名字不要加lib。
2、生成.h头文件
在工程的bin/classes中找到编译器生成的.class文件,会有一个MainActivity.class,使用如下命令生成头文件:
或者可以在环境变量中配置好classpath也可以,因为MainActivity中有我们引用的android中才有的SDK,注意类名要用全名且不能带.class拓展名。这样执行以后会在bin\classes中生成com_ldw_jni_MainActivity.h的头文件。里面的内容主要是生成的
JNIEXPORT jstring JNICALL Java_com_ldw_jni_MainActivity_getStringFromJNI
(JNIEnv *, jobject)函数,可以这样理解:.h文件相当于java里面的接口,而Java_com_ldw_jni_MainActivity_getStringFromJNI方法相当于接口里面的方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致。
3、接下来是编写本地方法,在工程下建立一个名为jni的目录,新建一个名为HelloWorld.c的文件,如下:
#include<string.h> #include<jni.h> jstring JNICALL Java_com_ldw_jni_MainActivity_getStringFromJNI(JNIEnv *env, jobject thiz) { return (*env)->NewStringUTF(env, "HelloWorld from JNI!"); }
返回一个字符串,JNI函数的说明网上有很多例子。
4、编写mk文件,mk文件的可以看看这里。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libHello LOCAL_SRC_FILES := HelloWorld.c include $(BUILD_SHARED_LIBRARY)
5、使用NDK编译.c文件,这里可以看看环境变量的配置。
此时在libs/armeabi目录下会多个.so文件。
运行一下程序试试看看效果如何。这里是源文件。
JNI很多高深的东西需要我们慢慢去摸索,我也是初学者,接下来可以尝试着编译一些开源的项目。
david,不要每次学习都是第一页哦
有道理,把上个博客的内容给补上来,先基础,然后再整点高级的。