最近在工作的开发过程中需要使用到JNI,但之前对于这块了解不够,因此恶补了一阵子,终于搞定了。好记性不如烂笔头,就顺便把一些关于JNI的开发整理出来,顺便增强自己的记忆,
1、 JNI背景介绍:
JNI(Java nativeinterface)是为了方便Java去调用C/C++实现的接口和方法的机制。Java是一种和平台无关的语言,而android是基于linux的的操作系统,只对上层应用提供C/C++的接口和方法,需要通过JNI把Java和C/C++连接起来。
Java通过JNI调用本地方法,而本地方法以库的形式保存在平台中。通过调用本地方法的实现,就可以将Java和系统调用联系起来,调用系统的一些模块、库进行交互。
1) 执行效率
对比C/C++与java的执行效率,主要是由于C/C++是编译型的语言,而java语言是解释性的语言,需要将java语言解释为二进制语言代码,计算机才能识别并运行。对于涉及大量运算的时候C/C++的执行效率会由于Java的执行效率。
2) 硬件控制
目前对于硬件设备的控制,目前大部分的设备的driver都是C实现了,通过JNI就可以实现Java对硬件设备的控制。
简单来说,JNI可以分为两部分java编程任务和C/C++编程任务的,这样可以让java部分和C/C++部分的工程师分别开发。由于之前学习的android应用开发忘得差不多了,为了顺便进行学习一下,所以就那android应用来
实现JNI的步骤大致可以分为六步:
Step1:编写java部分的本地方法;声明java中的本地方法,指定加载的lib文件,调用本地方法(在本例中通过android apk中事件响应来实现);
Step2:编译java部分的代码;需要将定义的java代码编译生成字节码,以便后续生产头文件;
Step3:创建C/C++的本地函数头文件;由于Java需要调用C/C++中的方法,因此需要在C/C++中声明方法,并进行定义。
Step4:编写C/C++本地函数的实现;实现本地函数的功能。
Step5:生成JNI的lib库文件;编译C/C++中实现的本地函数,生产lib文件(本例在linux平台运行,因此生产的为*.so文件);
Step6:运行java测试程序。查看运行的节目。
2、 JNI实现(step1):
首先看一下在java环境中对于JNI有关方法部分的code的编写
1) Java的代码中native方法的声明:
package com.led.api;
import android.R.bool;
public class LedNative {
static{
System.loadLibrary("LedJni");//Tip 1 加载对应的JNI库,LedJni是JNI库的名字,在实际加载动态库的时候会进行扩展为libLedJni.so
System.out.println("library path"+System.getProperty("java.library.path"));
}
public native static bool ledPowerOn(); //Tip2 声明一个native函数,声明为此方法的实现有native层实现
public native static bool ledPowerOff();
}
Java中本地方法的定义,在java类中,通过“native”关键字来声明本地方法。“native”关键字告知java编译器,在java中该方法仅声明,具体的实现由C/C++来实现。
如果没有增加native关键字则会提示函数需要实现“This method requires a body instead of a semicolon”。
其中System.loadLibrary("com_tcl_tv_jni");为java中加载具体实现本地方法的lib库文件,"com_tcl_tv_jni"为libcom_tcl_tv_jni.so,在loadLibrary中需要去掉“lib”和“.so”字符。为了保证能够在本地方法调用加加载本地方法的库文件,通常将System.loadLibrary调用放在本地方法声明的静态块中,避免在调用本地方法在加载库之前导致异常错误。
2)在应用中如何调用native方法
Android apk调用部分的code:
package com.led.control;
import com.led.api.LedNative; //Tip1 import对应的native类
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class LedControlActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button powerOn = (Button)this.findViewById(R.id.On);
Button poerOff = (Button)this.findViewById(R.id.Off);
powerOn.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
LedNative.ledPowerOn(); //Tip2 由于native方法声明为static,所以可以通过类名直接方法;如果为非static需要通过对象方法
}
});
poerOff.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
LedNative.ledPowerOff();
}
});
}
}
3) 编译java文件(step2)
编译android工程在bin目录下生产对应的字节码文件,以及对应的apk。
Java的native部分的总结
从上面的代码部分可以看出来,ledPowerOn和ledPowerOff函数前面都通过native关键字来声明,表明该函数需要在native层来实现
1)需要加载对应的lib库
2)需要使用关键字native方法类声明对应的函数。