注:编码工具是Android Studio。
目录
KotlinJniActivity代码
package com.android.jni.study.day22
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.android.jni.study.R
import kotlinx.android.synthetic.main.activity_kotlin_jni.*
class KotlinJniActivity : AppCompatActivity() {
// external 类似于 Java 的 native
private external fun sort(intArray: IntArray)
// 类似于 Java 的 static{}
companion object {
init {
System.loadLibrary("native-lib")
}
}
private val TAG = "KOTLIN_JNI_DEMO"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_kotlin_jni)
tv.setOnClickListener {
val intArray = intArrayOf(3, -1, 7, 99, 1, -5, 8, 19, 12, 17, 5, 4)
Log.e(TAG, "before sort:${intArray.joinToString()}")
sort(intArray)
Log.e(TAG, "after sort:${intArray.joinToString()}")
}
}
}
native代码
#include <jni.h>
#include <android/log.h>
#include <iostream>
#define TAG "KOTLIN_JNI_DEMO"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
int compare(const int *n1, const int *n2) {
return *n1 - *n2;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_day22_KotlinJniActivity_sort(JNIEnv *env, jobject thiz,
jintArray int_array) {
jint *array = env->GetIntArrayElements(int_array, 0);
jsize length = env->GetArrayLength(int_array);
qsort(array, length, sizeof(int),
reinterpret_cast<int (*)(const void *, const void *)>(compare));
env->ReleaseIntArrayElements(int_array, array, 0);
}
点击click输出
2021-12-23 20:57:18.314 25729-25729/com.wcc.jni.study E/KOTLIN_JNI_DEMO: before sort:3, -1, 7, 99, 1, -5, 8, 19, 12, 17, 5, 4
2021-12-23 20:57:18.316 25729-25729/com.wcc.jni.study E/KOTLIN_JNI_DEMO: after sort:-5, -1, 1, 3, 4, 5, 7, 8, 12, 17, 19, 99
KotlinJniActivity代码
package com.android.jni.study.day22
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.android.jni.study.R
import kotlinx.android.synthetic.main.activity_kotlin_jni.*
class KotlinJniActivity : AppCompatActivity() {
// external 类似于 Java 的 native
private external fun exception1()
private var name: String = "default"
// 类似于 Java 的 static{}
companion object {
init {
System.loadLibrary("native-lib")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_kotlin_jni)
tv.setOnClickListener {
exception1()
}
}
}
native代码
#include <jni.h>
#include <android/log.h>
#include <iostream>
#define TAG "KOTLIN_JNI_DEMO"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_day22_KotlinJniActivity_exception1(JNIEnv *env, jobject thiz) {
jclass jclz = env->GetObjectClass(thiz);
jfieldID field_id = env->GetFieldID(jclz, "nameNotExist", "Ljava/lang/String;");
jthrowable pJthrowable = env->ExceptionOccurred();
if(pJthrowable != 0) {
LOGE("有异常产生了...");
}
}
点击click输出:
2021-12-23 21:07:45.566 25825-25825/com.wcc.jni.study E/KOTLIN_JNI_DEMO: 有异常产生了...
2021-12-23 21:07:45.568 25825-25825/com.wcc.jni.study E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.wcc.jni.study, PID: 25825
java.lang.NoSuchFieldError: no "Ljava/lang/String;" field "nameNotExist" in class "Lcom/android/jni/study/day22/KotlinJniActivity;" or its superclasses
at com.android.jni.study.day22.KotlinJniActivity.exception1(Native Method)
at com.android.jni.study.day22.KotlinJniActivity.access$exception1(KotlinJniActivity.kt:9)
at com.android.jni.study.day22.KotlinJniActivity$onCreate$1.onClick(KotlinJniActivity.kt:29)
at android.view.View.performClick(View.java:7140)
at android.view.View.performClickInternal(View.java:7117)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27351)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
--------- beginning of system
2021-12-23 21:07:45.639 1937-2059/system_process E/InputDispatcher: channel '261409 com.wcc.jni.study/com.android.jni.study.day22.KotlinJniActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
2021-12-23 21:07:48.692 1937-2780/system_process E/TaskPersister: File error accessing recents directory (directory doesn't exist?).
其实nameNotExist在IDE里会报红,为了演示异常特意制造异常。
补救措施
native代码
#include <jni.h>
#include <android/log.h>
#include <iostream>
#define TAG "KOTLIN_JNI_DEMO"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_day22_KotlinJniActivity_exception1(JNIEnv *env, jobject thiz) {
jclass jclz = env->GetObjectClass(thiz);
jfieldID field_id = env->GetFieldID(jclz, "nameNotExist", "Ljava/lang/String;");
jthrowable pJthrowable = env->ExceptionOccurred();
if(pJthrowable != 0) {
LOGE("有异常产生了...");
env->ExceptionClear();// 清除异常
// 做补救
field_id = env->GetFieldID(jclz, "name", "Ljava/lang/String;");
jstring jstr = static_cast<jstring>(env->GetObjectField(thiz, field_id));
const char *str = env->GetStringUTFChars(jstr, 0);
LOGE("name is %s", str);
}
}
点击click输出
2021-12-23 21:15:58.968 26089-26089/com.wcc.jni.study E/KOTLIN_JNI_DEMO: 有异常产生了...
2021-12-23 21:15:58.968 26089-26089/com.wcc.jni.study E/KOTLIN_JNI_DEMO: name is default
可以从输出看出异常被清除了。
JniActivity代码
package com.android.jni.study;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class JniActivity extends AppCompatActivity {
// 加载本地库
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jni);
}
public static native void exception2() throws NoSuchFieldException;
public void click(View view) {
try {
exception2();
} catch (Exception e) {
Log.e("JNI", e.getMessage());
}
}
}
native代码
#include <jni.h>
#include <android/log.h>
#include <iostream>
#define TAG "JNI"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_JniActivity_exception2(JNIEnv *env, jclass clazz) {
jfieldID f_id = env->GetStaticFieldID(clazz, "nameNotExist", "Ljava/lang/String;");
jthrowable pJthrowable = env->ExceptionOccurred();
if (pJthrowable) {
LOGE("有异常产生了...");
env->ExceptionClear();// 清除异常
jclass jclz = env->FindClass("java/lang/NoSuchFieldException");
env->ThrowNew(jclz, "没有nameNotExist字段...");// 向Java层抛出一个新异常
}
}
点击click输出
2021-12-23 21:27:33.350 26394-26394/com.wcc.jni.study E/JNI: 有异常产生了...
2021-12-23 21:27:33.351 26394-26394/com.wcc.jni.study E/JNI: 没有nameNotExist字段...
JniActivity代码
package com.android.jni.study;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class JniActivity extends AppCompatActivity {
// 加载本地库
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jni);
}
private native void exception3();
private void show() throws Exception {
throw new NullPointerException("空指针异常...");
}
public void click(View view) {
exception3();
}
}
native代码
#include <jni.h>
#include <android/log.h>
#include <iostream>
#define TAG "JNI"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_android_jni_study_JniActivity_exception3(JNIEnv *env, jobject thiz) {
jclass jclz = env->GetObjectClass(thiz);
jmethodID m_id = env->GetMethodID(jclz, "show", "()V");
env->CallVoidMethod(thiz, m_id);
// 如果检查到异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();// 打印异常信息
env->ExceptionClear();// 清除异常
}
}
点击click输出
2021-12-23 21:34:28.475 26494-26494/com.wcc.jni.study W/System.err: java.lang.NullPointerException: 空指针异常...
2021-12-23 21:34:28.475 26494-26494/com.wcc.jni.study W/System.err: at com.android.jni.study.JniActivity.show(JniActivity.java:32)
2021-12-23 21:34:28.475 26494-26494/com.wcc.jni.study W/System.err: at com.android.jni.study.JniActivity.exception3(Native Method)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at com.android.jni.study.JniActivity.click(JniActivity.java:36)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:409)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at android.view.View.performClick(View.java:7140)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at android.view.View.performClickInternal(View.java:7117)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at android.view.View.access$3500(View.java:801)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at android.view.View$PerformClick.run(View.java:27351)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at android.os.Handler.handleCallback(Handler.java:883)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at android.os.Handler.dispatchMessage(Handler.java:100)
2021-12-23 21:34:28.476 26494-26494/com.wcc.jni.study W/System.err: at android.os.Looper.loop(Looper.java:214)
2021-12-23 21:34:28.477 26494-26494/com.wcc.jni.study W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7356)
2021-12-23 21:34:28.477 26494-26494/com.wcc.jni.study W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2021-12-23 21:34:28.478 26494-26494/com.wcc.jni.study W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
2021-12-23 21:34:28.478 26494-26494/com.wcc.jni.study W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)