Android JNI基础——利用JNI实现JAVA调用C++代码

一、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++调用数据库操作相关类来操作数据库提高数据库操作效率。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值