一、JNI与NDK简介
1、JNI(协议)
(1)定义
Java Native Interface,即 Java本地接口,相当于桥梁作用,一种协议;
即在 Java代码 里调用 C、C++等语言的代码 或 C、C++代码调用 Java 代码(互相调用)
Android系统架构中上层(框架层+应用层)JAVA通过JNI调用底层(Linux Kernel层)C;
JNI是 Java 调用 Native 语言的一种特性,是属于 Java 的,与 Android 无直接关系
(2)作用
实际使用中,Java需要与本地代码(Native code)进行交互,因为Java具备跨平台特点,所以Java与本地代码交互能力弱。可采用JNI特性增强Java与本地代码交互能力
2、NDK(工具)
(1)定义
Native Development Kit,是 Android的一个工具开发包;NDK是属于 Android 的,与Java并无直接关系
(2)作用
快速开发C、 C++的动态库,并自动将so和应用一起打包成 APK,即可通过 NDK在 Android中 使用 JNI与本地代码(如C、C++)交互
使Android开发的功能需在本地代码(C/C++)实现
(3)特点
运行效率高:在开发要求高性能的需求功能中,采用C/C++更加有效率,如使用本地代码(C/C++)执行算法,能大大提高算法的执行效率
代码安全性高:java是半解释型语言,容易被反编译后得到源代码,而本地代码(C/C++)不会,能提高系统安全性
功能扩展性好:可方便地使用其他开发语言的开源库,除Java开源库还可以用(C/C++)开源库
易于代码复用和移植
用本地代码(C/C++)开发的代码不仅可以在安卓使用,还可以嵌入其他类型平台使用
提供了把.so和.apk打包的工具(JNI只把.so文件放到文件系统特定位置)
NDK提供的库有限,仅用于处理算法效率和敏感问题
提供了交叉编译器,用于生成特定的CPU平台动态库
3、JNI与NDK关系
JNI是实现的目的(java与本地语言交互的接口/协议),NDK是Android中实现JNI的工具(Android工具开发包)
二、利用JNI实现JAVA调用C++代码
1、新建一个JNI_Domo的工程,然后创建JNI类声明native方法。
//JNI.java
package com.example.jni_domo;
public class JNI {
static {
System.loadLibrary("JNI_Domo");
}
public static native String sayHello();
}
2、在main目录下新建cpp目录用于存放cpp文件,然后在目录下新建hello.cpp和CMakeList.txt文件。
其中hello.cpp用于编写C++代码,CMakeList.txt用于编译C++代码。
//hello.cpp
#include <jni.h>
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_jni_1domo_JNI_sayHello(JNIEnv *env, jclass clazz) {
// TODO: implement sayHello()
const char * text = "I am from C";
return (*env).NewStringUTF(text);
}
CMakeList.txt
cmake_minimum_required(VERSION 3.4.1)
project("JNI_Domo")
add_library(
JNI_Domo
SHARED
hello.cpp)
target_link_libraries(
JNI_Domo)
然后修改MainActivity代码,调用JNI类方法
package com.example.jni_domo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView JniTextView;
private Button JniScheduleBtn;
private JniClickListener JniClickListener = new JniClickListener();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
public void initView(){
JniTextView = (TextView) findViewById(R.id.TextView);
JniScheduleBtn = (Button) findViewById(R.id.button);
JniScheduleBtn.setOnClickListener(JniClickListener);
}
public class JniClickListener implements View.OnClickListener{
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button:
JniTextView.setText(JNI.sayHello());
}
}
}
}
activity_main.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
<TextView
android:id="@+id/TextView"
android:layout_width="wrap_content"
android:layout_height="15dp"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
最后在app目录下的build.gradle文件追加如下语句:
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.jni_domo'
compileSdk 32
defaultConfig {
applicationId "com.example.jni_domo"
minSdk 29
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
点Sync Now后就可以编译了。
后续学习,可以在JNI中使用C++加载Linux动态链接库(.so文件),还可以通过Linux标准IO接口(Open、Close、Read、Write、Ioctrl等)调用Linux内核代码。
当然也可以在JNI中,使用C++调用数据库操作相关类来操作数据库提高数据库操作效率。