为什么使用JNI?
使用JNI可以使Java语言和本地C/C++交互:
- Java提供的本地类库无法满足需要,在大规模的数学运算、视音频处理等方面C/C++具有更高的效率。
- Java并不能操作硬件,而C/C++能够直接操作硬件,发挥硬件的最佳性能
- C/C++已经有十分丰富的开源库,使用JNI避免重复造车,在Java或者Android开发过程中具有十分重要的作用
使用JNI调用本地方法库的基本步骤:
- 第一,编写C/C++程序
- 第二,编写Android.mk文件,用以规定编译规则
- 第三,使用NDK编译第一步中的C/C++程序获得能够被我们调用的.so库文件
- 第四,编写Java中的本地方法(没有具体的方法实现)
1.编写C/C++程序
#include <stdio.h>
#include <jni.h>
#include "com_example_ndkhelloworld_HelloNDK.h"
//jstring Java_com_example_ndkhelloworld_HelloNDK_helloFromNDK(JNIEnv* env , jobject obj){
// return (*(*env)).NewStringUTF(env ,"HelloFromNDK") ;
//}
JNIEXPORT jstring JNICALL Java_com_example_ndkhelloworld_HelloNDK_helloFromNDK
(JNIEnv * env, jobject obj)
{
return (*(*env)).NewStringUTF(env ,"helloFromNDK") ;
}
JNIEXPORT jstring JNICALL Java_com_example_ndkhelloworld_HelloNDK_hello_1From_1NDK
(JNIEnv * env, jobject obj)
{
return (*(*env)).NewStringUTF(env ,"hello_From_NDK") ;
}
注意:在编写C/C++方法时要注意方法的签名:java+包名+类名+方法名,方法的签名和要和Java中的包名类名本地方法名一一对应。
2.编写Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := helloworld
LOCAL_SRC_FILES := HelloWorld.c
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:表示获取本地目录。
CLEAR_VAR:表示初始化变量
LOCAL_MODULE:表示输出本地类库的名字。
LOCAL_SRC_FILES:表示编译的源文件
3.使用NDK编译CC++程序
- 使用NDK中的ndk-build编译C/C++程序
- 编译以后产生的.so本地文件前缀lib+helloworld.so
4编写Java本地方法
package com.example.ndkhelloworld;
public class HelloNDK {
public native String helloFromNDK() ;
public native String hello_From_NDK() ;
}
注意:包名+类名+方法名要与C/C++程序中的包名+类名+方法名一致,否则会无法调用。
5.在MainActivity中调用
- 首先,要在静态代码块中加载.so库,在加载类库时要去掉lib前缀。
package com.example.ndkhelloworld;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class MainActivity extends Activity {
static{
System.loadLibrary("helloworld") ;
}
private HelloNDK helloNDK = new HelloNDK() ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = new TextView(this) ;
textView.setText(helloNDK.helloFromNDK() + "\n" + helloNDK.hello_From_NDK()) ;
setContentView(textView) ;
}
}