JNI访问Java类函数
在之前demo的基础上添加几个方法,测试在JNI编程中怎么访问Java类中的函数
在JNI和Java中访问类属性有什么区别:
对以下这几种类型的函数进行访问
构造函数的访问是一个特例
在JNI中访问Java函数要加上函数描述符
调用构造函数
extern "C"
JNIEXPORT jobject JNICALL
Java_com_xiaoeryu_reflectiontest_MainActivity_callInit(JNIEnv *env, jobject thiz) {
// TODO: implement callInit()
// public Test(String arg, int arg2)
jclass TestJclass = env->FindClass("com/xiaoeryu/reflectiontest/Test");
jmethodID con_mid = env->GetMethodID(TestJclass, "<init>", "(Ljava/lang/String;I)V");
jstring arg0 = env->NewStringUTF("i am from callInit");
jobject obj = env->NewObject(TestJclass, con_mid, arg0, 100);
return obj;
}
构造函数调用的时候函数名使用
代替
调用静态函数
extern "C"
JNIEXPORT void JNICALL
Java_com_xiaoeryu_reflectiontest_MainActivity_callStaticFunc(JNIEnv *env, jobject thiz) {
// TODO: implement callStaticFunc()
// public static void publicStaticFunc()
jclass Testjclass = env->FindClass("com/xiaoeryu/reflectiontest/Test");
jmethodID publicStaticFunc_mid = env->GetStaticMethodID(Testjclass, "publicStaticFunc", "()V");
env->CallStaticVoidMethod(Testjclass, publicStaticFunc_mid);
// private static void privateStaticFunc()
jmethodID privateStaticFunc_mid = env->GetStaticMethodID(Testjclass, "privateStaticFunc",
"()V");
env->CallStaticVoidMethod(Testjclass, privateStaticFunc_mid);
// public static int publicStaticFunc_int(int a){
// Log.i("xiaoeryu", "i am from publicStaticFunc_int");
// return 111 + a;
// }
jmethodID publicStaticFunc_int_mid = env->GetStaticMethodID(Testjclass, "publicStaticFunc_int",
"(I)I");
jint res_value = env->CallStaticIntMethod(Testjclass, publicStaticFunc_int_mid, 001);
__android_log_print(4, "xiaoeryu->jni", "publicStaticFunc_int->%d", res_value);
// public static String publicStaticFunc_string(String arg){
// Log.i("xiaoeryu", "i am from publicStaticFunc_int");
// return "publicStaticFunc_string->" + arg;
// }
jmethodID publicStaticFunc_str_mid = env->GetStaticMethodID(Testjclass,
"publicStaticFunc_string",
"(Ljava/lang/String;)Ljava/lang/String;");
jstring arg_str = env->NewStringUTF("i am from jni");
jstring ret_str = static_cast<jstring>(env->CallStaticObjectMethod(Testjclass,
publicStaticFunc_str_mid,
arg_str));
const char *content = env->GetStringUTFChars(ret_str, nullptr);
__android_log_print(4, "xiaoeryu->jni", "publicStaticFunc_string->%s", content);
}
JNI调用java函数不分public/private
call的类型也分为引用类型
CallStaticObjectMethod
和基础类型CallStaticVoidMethod、CallStaticIntMethod 等。。。
调用非静态函数
extern "C"
JNIEXPORT void JNICALL
Java_com_xiaoeryu_reflectiontest_MainActivity_callNonStaticFunc(JNIEnv *env, jobject thiz) {
// TODO: implement callNonStaticFunc()
jclass TestJclass = env->FindClass("com/xiaoeryu/reflectiontest/Test");
jmethodID con_mid = env->GetMethodID(TestJclass, "<init>", "(Ljava/lang/String;I)V");
jstring arg = env->NewStringUTF("i am from callInit");
jobject testObj = env->NewObject(TestJclass, con_mid, arg, 100);
// public void publicFunc()
jmethodID publicFunc_mid = env->GetMethodID(TestJclass, "publicFunc", "()V");
// void CallVoidMethod(jobject obj, jmethodID methodID, ...)
env->CallVoidMethod(testObj, publicFunc_mid);
// private String privateFunc_str(int a, String b)
jmethodID privateFunc_str_mid = env->GetMethodID(TestJclass, "privateFunc_str", "(ILjava/lang/String;)Ljava/lang/String;");
jstring arg1 = env->NewStringUTF("i am from jni");
// 调用不同CallObjectMethod的区别
// CallObjectMethod
// CallObjectMethodA
// CallObjectMethodV
// jstring ret_str = static_cast<jstring>(env->CallObjectMethod(testObj, privateFunc_str_mid, 002,
// arg1));
jvalue args[2];
args[0].i = 003;
args[1].l = arg1;
jstring ret_str = static_cast<jstring>(env->CallObjectMethodA(testObj, privateFunc_str_mid,
args));
const char* result_ptr = env->GetStringUTFChars(ret_str, nullptr);
__android_log_print(4, "xiaoeryu->jni", "privateFunc_str->%s", result_ptr);
// private int[] privateFunc_array(int a)
jmethodID privateFunc_array_mid = env->GetMethodID(TestJclass, "privateFunc_array", "(I)[I");
jintArray array_obj = static_cast<jintArray>(static_cast<jarray>(env->CallObjectMethod(testObj,
privateFunc_array_mid,
20)));
jint* array_ptr = env->GetIntArrayElements(array_obj, nullptr);
for (int i = 0; i < env->GetArrayLength(array_obj); ++i) {
__android_log_print(4, "xiaoeryu->jni", "array[%d]->%d", i, array_ptr[i]);
}
}
非静态函数不能直接调用,需要先使用
NewObject()
实例化之后才能调用每个Call函数有三种实现:这三种接口都可以完成函数的调用,只是参数会有区别
CallXXXMethod:一般方式:处理变长参数时可能不够灵活
CallXXXMethodA:使用
jvalue
数组传递参数,可以更方便的处理变长参数 CallXXXMethodV:使用
va_list
传递参数,也是为了处理变长参数。形式更加灵活,但是需要注意正确处理参数的类型和顺序
调用父类函数
例如我们如果要把这个父类的onCreate()以及它里面的一些调用方法进行本地化写成JNI函数应该怎么做呢
因为它是一个入口函数所以有很多壳会这么做,接下来看一下它是怎么实现的
PS:新版的布局函数调用出错了,换了老版的布局函数。以后再解决
binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot());
换了老版的
setContentView(R.layout.activity_main); TextView tv = findViewById(R.id.sample_text);
extern "C"
JNIEXPORT void JNICALL
Java_com_xiaoeryu_reflectiontest_MainActivity_onCreate(JNIEnv *env, jobject thiz,
jobject saved_instance_state) {
// super.onCreate(savedInstanceState);
// TODO: implement onCreate()
// 有三种方法都可以获取到当前类引用
jclass AppCompatActivity_jclass = env->FindClass("androidx/appcompat/app/AppCompatActivity");
jclass MainActivity_jclass1 = env->FindClass("com/xiaoeryu/reflectiontest/MainActivity");
jclass MainActivity_jclass2 = env->GetObjectClass(thiz);
// 获取父类
jclass AppCompatActivity_jclass2 = env->GetSuperclass(MainActivity_jclass2);
// protected native void onCreate(Bundle savedInstanceState);
// super.onCreate(savedInstanceState);
jmethodID onCreate_mid = env->GetMethodID(AppCompatActivity_jclass, "onCreate", "(Landroid/os/Bundle;)V");
// void CallNonvirtualVoidMethod(jobject obj, jclass clazz,
// jmethodID methodID, ...)
// 当前类对象是MainActivity类对象
env->CallNonvirtualVoidMethod(thiz, AppCompatActivity_jclass, onCreate_mid,saved_instance_state);
// 然后就可以调用Java中的方法了
jstring arg1 = env->NewStringUTF("xiaoeryu");
jstring arg2 = env->NewStringUTF("onCreate is Called!");
// 使用Log也需要先找到它所在的类名创建类引用
jclass LogJclass = env->FindClass("android/util/Log");
// .i是一个静态函数可以在JNI中直接调用,所以就直接获取MethodID
// public static int i(String tag, String msg)
jmethodID Log_i_mid = env->GetStaticMethodID(LogJclass, "i", "(Ljava/lang/String;Ljava/lang/String;)I");
jint result = env->CallStaticIntMethod(LogJclass, Log_i_mid, arg1, arg2);
__android_log_print(4, "xiaoeryu->jni", "Log_i_mid->%d", result);
/* setContentView(R.layout.activity_main);
* TextView tv = findViewById(R.id.sample_text);
* Test testobj = (Test) callInit();
* Log.i("xiaoeryu", testobj.flag);
*/
jmethodID setContentView_mid = env->GetMethodID(MainActivity_jclass2, "setContentView", "(I)V");
jclass R_layoutjclass = env->FindClass("com/xiaoeryu/reflectiontest/R$layout");
jfieldID activity_main_fieldid = env->GetStaticFieldID(R_layoutjclass, "activity_main", "I");
jint activity_main_value = env->GetStaticIntField(R_layoutjclass, activity_main_fieldid);
env->CallVoidMethod(thiz, setContentView_mid, activity_main_value);
// TextView tv = findViewById(R.id.sample_text);
jmethodID findViewById_mid = env->GetMethodID(MainActivity_jclass2, "findViewById", "(I)Landroid/view/View;");
jclass R_idjclass = env->FindClass("com/xiaoeryu/reflectiontest/R$id");
jfieldID sample_text_fieldid = env->GetStaticFieldID(R_idjclass, "sample_text", "I");
jint sample_text_value = env->GetStaticIntField(R_idjclass, sample_text_fieldid);
env->CallObjectMethod(thiz, findViewById_mid, sample_text_value);
/*
* Test testobj = (Test) callInit();
* Log.i("xiaoeryu", testobj.flag);
* */
jmethodID callInit_mid = env->GetMethodID(MainActivity_jclass2, "callInit", "()Ljava/lang/Object;");
jobject testobj = env->CallObjectMethod(thiz,callInit_mid);
jclass testjcalss = env->FindClass("com/xiaoeryu/reflectiontest/Test");
jfieldID flagjfield = env->GetFieldID(testjcalss, "flag", "Ljava/lang/String;");
jstring flagvalue = static_cast<jstring>(env->GetObjectField(testobj, flagjfield));
jint result_flag = env->CallStaticIntMethod(LogJclass, Log_i_mid, arg1, flagvalue);
__android_log_print(4, "xiaoeryu->jni", "flag->%d", result_flag);
}
通过对
Oncreate
以及它里面调用的实现可以发现,任意一个Java实现的函数都可以换成JNI来实现
- 标题: JNI访问Java类函数
- 作者: xiaoeryu
- 创建于 : 2023-10-14 21:38:59
- 更新于 : 2023-10-19 11:19:34
- 链接: https://github.com/xiaoeryu/2023/10/14/JNI访问Java类函数/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论