1、实现效果
Screenshot_20220827-120825.png
2、Java代码
package com.hvm.vender.jni_01;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.hvm.vender.jni_01.databinding.ActivityMainBinding;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
public static String TAG = MainActivity.class.getSimpleName() + "_JAVA";
// Used to load the 'jni_01' library on application startup.
static {
System.loadLibrary("jni_01");
}
private ActivityMainBinding binding;
public static final int NUMBER = 100;
public String name = "daxiaa"; // 签名:Ljava/lang/String;
public static int age = 30; // 签名:I
public int count = 800;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
initListener();
}
private void initListener() {
binding.btnUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "修改之之前的值: " + name);
changeName();
Log.d(TAG, "修改之后的值: " + name);
}
});
binding.btnUpdate2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "修改之之前的值: " + age);
changeAge();
Log.d(TAG, "修改之后的值: " + age);
}
});
binding.btnCallback.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
callBack();
}
});
binding.btnCallback2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String data = javaToNativeNoParams();
Log.d(TAG, "Java调用C++函数拿到的返回值: " + data);
}
});
binding.btnJavaC.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int age = 29;
String sex = "boy";
int[] array = {1, 2, 3, 7, 8, 7};
String[] strs = new String[]{"daxiaa", "pig", "dog"};
javaToNativeParams(age, sex, array, strs);
}
});
binding.btnJavaCObj.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Student student = new Student();
javaToNativeObj(student, "hello world");
}
});
binding.btnCJavaObj.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Student student = nativeNewObj();
Log.d(TAG, "C++创建的对象返回值: "+student.toString());
}
});
binding.btnGlobalReference.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
globalReference();
}
});
binding.btnExtern.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
extern();
}
});
}
/**
* extern关键字测试
*/
native void extern();
/**
* 全局引用测试
*/
native void globalReference();
/**
* native创建Java对象
* @return
*/
native Student nativeNewObj();
/**
* java ->native传递对象
* @param student
* @param hello_world
*/
native void javaToNativeObj(Student student, String hello_world);
/**
* java->native传递基本类似、String 数组
*
* @param age
* @param sex
* @param array
* @param strs
*/
native void javaToNativeParams(int age, String sex, int[] array, String[] strs);
/**
* java->native无参数
* @return
*/
native String javaToNativeNoParams();
/**
* native调用java函数
* 有返回值
* @param a
* @param b
* @return
*/
public String nativeToJava2(int a, String b) {
Log.d(TAG, " C++调用Java中的函数 a = " + a + ",b = " + b);
return "c++ is pig";
}
/**
* native调用java函数
* 无返回值,有参数
* @param a
* @param b
*/
public void nativeToJava(int a, String b) {
Log.d(TAG, "nativeToJava: C++调用Java中的函数a = " + a + ",b = " + b);
}
/**
* native调用java函数
* 无返回值,无参数
*/
native void callBack();
//native 修改 name、age的值
native void changeName();
//native 静态的本地方法
native static void changeAge();
}
3、Native代码
#include <jni.h>
#include <string>
// NDK工具链里面的 log 库 引入过来
#include <android/log.h>
#define TAG "MainActivity_C"
// ... 我都不知道传入什么 借助JNI里面的宏来自动帮我填充
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
//// extern "C": 必须采用C的编译方式,为什么,请看JNIEnv内部源码
//// // 无论是C还是C++ 最终是调用到 C的JNINativeInterface,所以必须采用C的方式 extern "C"
//// 函数的实现
//extern "C"
//
//JNIEXPORT // 标记该方法可以被外部调用(VS上不加入 运行会报错, AS上不加入运行没有问题)
//// Linux运行不加入,不报错, Win 你必须加入 否则运行报错, MacOS 还不知道
//
//jstring // Java <---> native 转换用的
//
//JNICALL // 代表是 JNI标记,可以少
//
//// Java_包名_类名_方法名 ,注意:我们的包名 _ native _1
//
//// JNIEnv * env JNI:的桥梁环境 300多个函数,所以的JNI操作,必须靠他
//
//// jobject jobj 谁调用,就是谁的实例 MainActivity this
//// jclass clazz 谁调用,就是谁的class MainActivity.class
/**
* 实现在c中修改java中的成员属性
* 修改普通的成员属性
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_hvm_vender_jni_101_MainActivity_changeName(JNIEnv *env, jobject thiz) {
//1、获取class
jclass j_class = env->GetObjectClass(thiz);
//2、获取属性id
//j_class、属性名称、属性签名
jfieldID j_Id = env->GetFieldID(j_class, "name", "Ljava/lang/String;");
//3、将属性转换成jni中的桥梁 string转换成jstring
jstring j_name = static_cast<jstring>(env->GetObjectField(thiz, j_Id));
//4、将jstring转换成c、c++ char*进行打印
char *c_name = const_cast<char *>(env->GetStringUTFChars(j_name, NULL));
//5、打印结果
LOGD("在c中获取到的name:%s\n", c_name);
//6、修改java 中name的值,先创建一个jstring
jstring j_tem = env->NewStringUTF("dog");
//7、修改
env->SetObjectField(thiz, j_Id, j_tem);
//测试获取修改int类型的数据
jfieldID count_jfieldId = env->GetFieldID(j_class, "count", "I");
jint j_count = env->GetIntField(thiz, count_jfieldId);
int count = j_count;
LOGD("在c中获取到的coun:%d\n", count);
}
/**
* 实现在c中修改java中的静态的成员属性
*
*
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_hvm_vender_jni_101_MainActivity_changeAge(JNIEnv *env, jclass j_class) {
//1、获取属性ID
jfieldID jfield_Id = env->GetStaticFieldID(j_class, "age", "I");
//2、java中的int age转换成桥梁 jint
jint j_age = env->GetStaticIntField(j_class, jfield_Id);
int c_age = j_age;
//3、打印结果
LOGD("在c中获取到的age:%d\n", c_age);
//4、修改age的值
jint temp = 100;
env->SetStaticIntField(j_class, jfield_Id, temp);
}
/**
* 实现c++调用java中的函数
* 无返回值
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_hvm_vender_jni_101_MainActivity_callBack(JNIEnv *env, jobject thiz) {
//1、获取方法id
jclass j_class = env->GetObjectClass(thiz);
jmethodID jmethod_Id = env->GetMethodID(j_class, "nativeToJava", "(ILjava/lang/String;)V");
//2、执行方法
jstring temp = env->NewStringUTF("hello world");
jint number = 100;
env->CallVoidMethod(thiz, jmethod_Id, number, temp);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_hvm_vender_jni_101_MainActivity_javaToNativeNoParams(JNIEnv *env, jobject thiz) {
LOGD("Java调用C++中的函数");
//1、获取方法id
jclass j_class = env->GetObjectClass(thiz);
jmethodID jmethod_Id = env->GetMethodID(j_class, "nativeToJava2",
"(ILjava/lang/String;)Ljava/lang/String;");
//2、执行方法
jstring temp = env->NewStringUTF("hello world");
jint number = 800;
jstring jstring_temp = static_cast<jstring>(env->CallObjectMethod(thiz, jmethod_Id, number,
temp));
char *data = const_cast<char *>(env->GetStringUTFChars(jstring_temp, NULL));
LOGD("C++调用Java拿到的值:%s\n", data);
jstring result = env->NewStringUTF("java is pig");
return result;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hvm_vender_jni_101_MainActivity_javaToNativeParams(JNIEnv *env, jobject thiz, jint age,
jstring sex, jintArray array,
jobjectArray strs) {
//1、基本数据类型
LOGD("基本数据类型:%d", age);
//2、字符串
const char *sexStr = env->GetStringUTFChars(sex, NULL);
LOGD("字符串:%s", sexStr);
//3、操作int类型数组
jint *jintArray = env->GetIntArrayElements(array, NULL);
int length = env->GetArrayLength(array);
//遍历指针
for (int i = 0; i < length; ++i) {
LOGD("遍历int类型数组:%d", *(jintArray + i));
}
//释放数组
env->ReleaseIntArrayElements(array, jintArray, 0);
//GetIntArrayElements和ReleaseIntArrayElements一一对应
//4、操作对象,字符串数组
int size = env->GetArrayLength(strs);
for (int i = 0; i < size; ++i) {
jstring jstringStr = static_cast<jstring>(env->GetObjectArrayElement(strs, i));
//char*->jstring
// env->NewStringUTF()
//jstring->char*
const char *str = env->GetStringUTFChars(jstringStr, NULL);
LOGD("遍历String类型数组:%s", str);
env->ReleaseStringUTFChars(jstringStr, str);
//GetStringUTFChars和ReleaseStringUTFChars一一对应
}
}
/**
* java调用native传递对象
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_hvm_vender_jni_101_MainActivity_javaToNativeObj(JNIEnv *env, jobject thiz, jobject student,
jstring str) {
jclass j_class = env->GetObjectClass(student);
jstring j_string = env->NewStringUTF("daxiaa");
//调用Student中的函数 setName
jmethodID j_methodId = env->GetMethodID(j_class, "setName", "(Ljava/lang/String;)V");
env->CallVoidMethod(student, j_methodId, j_string);
//调用student中的静态方方达
jmethodID j_static_methodId = env->GetStaticMethodID(j_class, "show", "()V");
env->CallStaticVoidMethod(j_class, j_static_methodId);
//调用getName 带返回值的函数
jmethodID j_return_methodId = env->GetMethodID(j_class, "getName", "()Ljava/lang/String;");
jstring jstringName = static_cast<jstring>(env->CallObjectMethod(student, j_return_methodId));
const char *nameChar = env->GetStringUTFChars(jstringName, NULL);
LOGD("调用Student对象中的getName函数返回值:%s", nameChar);
env->ReleaseStringUTFChars(jstringName, nameChar);
}
/**
*native创建java的Student对象
*/
extern "C"
JNIEXPORT jobject JNICALL
Java_com_hvm_vender_jni_101_MainActivity_nativeNewObj(JNIEnv *env, jobject thiz) {
//1、通过包名+类名拿到Student的class
char *calssName = "com/hvm/vender/jni_01/Student";
jclass j_class = env->FindClass(calssName);
jstring name = env->NewStringUTF("Pig");
//创建对象 实例化此Student对象 C++ new Student
//(1)创建对象方式1 AllocObject方式,只示例对象,不会调用构造函数
jobject j_object_student = env->AllocObject(j_class);
jmethodID j_methodId = env->GetMethodID(j_class, "setName", "(Ljava/lang/String;)V");
//3、调用setName函数
env->CallVoidMethod(j_object_student, j_methodId, name);
//(2)创建对象方式3 NewObject 方式,会调用构造函数
//获取构造方法的id
jmethodID constructMethodId = env->GetMethodID(j_class, "<init>", "(Ljava/lang/String;I)V");
jobject j_object_student2 = env->NewObject(j_class, constructMethodId, name,
150);///NewObject,会调用构造函数
jmethodID j_getAgemethodId = env->GetMethodID(j_class, "getAge", "()I");
jint age = env->CallIntMethod(j_object_student2, j_getAgemethodId);
LOGD("调用Student对象中的getAge函数返回值:%d", age);
//用完释放
// env->DeleteLocalRef(j_class);
//env->DeleteLocalRef(j_object_student2);
//env->DeleteLocalRef(j_object_student);
char *personClassName = "com/hvm/vender/jni_01/Person";
jclass personCalss = env->FindClass(personClassName);
jobject jobjectPerson = env->AllocObject(personCalss);
jmethodID jmethodIdSetName = env->GetMethodID(personCalss, "setName", "(Ljava/lang/String;)V");
//设置personName属性
env->CallVoidMethod(jobjectPerson, jmethodIdSetName, env->NewStringUTF("person is pig"));
//设置person属性
jfieldID j_fieldIdPerson = env->GetFieldID(j_class, "person", "Lcom/hvm/vender/jni_01/Person;");
env->SetObjectField(j_object_student2, j_fieldIdPerson, jobjectPerson);
return j_object_student2;
}
jclass j_class;
extern "C"
JNIEXPORT void JNICALL
Java_com_hvm_vender_jni_101_MainActivity_globalReference(JNIEnv *env, jobject thiz) {
//这种方式创建全局引用可行
if (!j_class) {
char *personClassName = "com/hvm/vender/jni_01/Person";
jclass temp = env->FindClass(personClassName);
j_class = static_cast<jclass>(env->NewGlobalRef(temp));
}
//不能用这种方式创建全局引用
// if (!j_class) {
// char *personClassName = "com/hvm/vender/jni_01/Person";
// j_class = env->FindClass(personClassName);
// }
jmethodID jmethod_Id = env->GetMethodID(j_class, "<init>", "()V");
jobject j_object = env->NewObject(j_class, jmethod_Id);
LOGD("全局引用测试");
}
//extern 关键字声明,extern-lib.cpp中实现
extern int age;
extern void show();
extern "C"
JNIEXPORT void JNICALL
Java_com_hvm_vender_jni_101_MainActivity_extern(JNIEnv *env, jobject thiz) {
show();
}
//
// Created by mayn on 2022/8/27.
//
// NDK工具链里面的 log 库 引入过来
#include <android/log.h>
#define TAG "MainActivity_C"
// ... 我都不知道传入什么 借助JNI里面的宏来自动帮我填充
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
int age = 99;
void show() {
LOGD("extern %d", age);
}
源码
https://gitee.com/daxiaa/jni-ndk.git
网友评论