JNI学习笔记——(一)入门

注:编码工具是Android Studio。

目录

创建Android Studio编写JNI代码环境

JNI是什么?

javah命令生成native方法签名

案例一:Native修改Java类属性值

案例二:Native调用Java类方法 

Java各种数据类型的签名


创建Android Studio编写JNI代码环境

        File -> New Project -> Native C++。

JNI是什么?

        JNI是JDK提供的一种能够让Java和Native之间互相操作的机制。

javah命令生成native方法签名

        在Java中用native定义本地方法,具体的实现用C/C++实现,Java中可以直接调用native修饰的方法,调用它相当于调用了C/C++实现的方法体。

        JNI有一套固定的native方法签名格式,可以用JDK自带的javah命令生成对应的方法签名。

在MainActivity中定义一个native方法,getStringFromNative,返回值为String,没有形式参数。

package com.wcc.jni.study;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // 加载本地库
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(getStringFromNative());
    }

    // 本地方法在Java中只有声明,没有方法体
    private native String getStringFromNative();
}

在命令行运行javah命令

D:\Android\AndroidStudioProjects\JniStudy\app\src\main\java>javah com.android.jni.study.MainActivity

会在java目录下生成一个.h格式的头文件,里面有native的方法签名。

com_android_jni_study_MainActivity.h

内容

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_android_jni_study_MainActivity */

#ifndef _Included_com_android_jni_study_MainActivity
#define _Included_com_android_jni_study_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_android_jni_study_MainActivity
 * Method:    getStringFromNative
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_android_jni_study_MainActivity_getStringFromNative
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

将头文件复制到cpp目录下。

在cpp文件中,引入头文件,并实现方法。

#include <jni.h>
#include "com_android_jni_study_MainActivity.h"

extern "C" // 必须,所有代码以C形式运行
JNIEXPORT
jstring // 对应Java的String
JNICALL// 可以省略
Java_com_android_jni_study_MainActivity_getStringFromNative
        (JNIEnv *env, // JNI的核心,Java和Native的互相操作都靠env
         jobject jobj// Java中的native方法声明在哪个类,就传哪个类的对象
        ) {
        std::string hi = "hi from native";
        return env->NewStringUTF(hi.c_str());
}

运行结果:

案例一:Native修改Java类属性值

MainActivity代码

package com.android.jni.study;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // 加载本地库
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        updateText();
        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(text);
    }

    private String text = "default";

    private native void updateText();
}

Native代码

#include <jni.h>
#include <string>


extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_MainActivity_updateText(JNIEnv *env, jobject thiz) {
    // 获取jobject对应的jclass
    jclass  jclz = env->GetObjectClass(thiz);
    // 获取Java类属性FieldID
    jfieldID f_id = env->GetFieldID(
            jclz,
            "text",// Java类属性名
            "Ljava/lang/String;"// Java类属性类型签名
            );
    // 创建jstring
    jstring jstr = env->NewStringUTF("NewValue");
    // 通过FieldID修改Java类属性值
    env->SetObjectField(thiz, f_id, jstr);
}

运行结果

案例二:Native调用Java类方法 

MainActivity代码

package com.android.jni.study;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // 加载本地库
    static {
        System.loadLibrary("native-lib");
    }

    private TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.sample_text);
    }

    public native void callJavaMethod();

    private void print(){
        Log.e("Main", "Call From Native");
    }

    public void click(View view) {
        callJavaMethod();
    }
}

Native代码

#include <jni.h>
#include <string>


extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_MainActivity_updateText(JNIEnv *env, jobject thiz) {
    // 获取jobject对应的jclass
    jclass  jclz = env->GetObjectClass(thiz);
    // 获取Java类属性FieldID
    jfieldID f_id = env->GetFieldID(
            jclz,
            "text",// Java类属性名
            "Ljava/lang/String;"// Java类属性类型签名
            );
    // 创建jstring
    jstring jstr = env->NewStringUTF("NewValue");
    // 通过FieldID修改Java类属性值
    env->SetObjectField(thiz, f_id, jstr);
}extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_MainActivity_callJavaMethod(JNIEnv *env, jobject thiz) {
    // 获取jobject的jclass
    jclass jclz = env->GetObjectClass(thiz);
    // 获取methodID
    jmethodID m_id = env->GetMethodID(
            jclz,
            "print",// 方法名
            "()V"// 方法签名
            );
    // 通过methodID调用Java类方法
    env->CallVoidMethod(
            thiz,
            m_id
            );
}

运行结果

Java各种数据类型的签名

boolean --- Z
char --- C
byte --- B
short --- S
int --- I
long --- J
float --- F
double --- D
void --- V
引用类型 --- L全类名; 其中.用/代替,如:String的签名Ljava/lang/String;
数组 --- [元素签名,如:int[]的签名[I

        可以用JDK的javap命令查看某个类中的方法和属性的签名,如:javap -s -p MainActivity,其中MainActivity是Class文件。

        上述命令的输出格式如下:

public class com.android.jni.study.MainActivity extends androidx.appcompat.app.AppCompatActivity {
  private android.widget.TextView tv;
    descriptor: Landroid/widget/TextView;
  public com.android.jni.study.MainActivity();
    descriptor: ()V

  protected void onCreate(android.os.Bundle);
    descriptor: (Landroid/os/Bundle;)V

  public native void callJavaMethod();
    descriptor: ()V

  private void print();
    descriptor: ()V

  public void click(android.view.View);
    descriptor: (Landroid/view/View;)V

  static {};
    descriptor: ()V
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值