JNI異常處理和快取策略

鋸齒流沙發表於2017-12-26

異常:程式在執行期間沒有按照正常的程式邏輯執行,在執行過程當中出現了某種錯誤,導致程式崩潰。

作用: 1、保證Java程式碼可以執行

2、補救措施保證C程式碼繼續執行

由於JNI自己丟擲的異常,在Java層無法被捕捉,只能在C層清空。而使用者通過ThrowNew丟擲的異常,可以在Java層捕捉。

public class MyException {
	
	public native void exeception();
	
	private String name = "xiaoming";
	
	public static void main(String[] args) {
		MyException m = new MyException();
		try {
			m.exeception();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println("nihao");
	}
	
	//載入動態庫
	static {
		System.loadLibrary("ConsoleApplication1");
	}

}

複製程式碼

native方法實現

JNIEXPORT void JNICALL Java_com_lwj_test_MyException_exeception
(JNIEnv *env, jobject jobj){
	jclass cls = (*env)->GetObjectClass(env, jobj);
	jfieldID fid = (*env)->GetFieldID(env, cls, "myname", "Ljava/lang/String;");
	//檢測是否發生Java異常
	jthrowable exception = (*env)->ExceptionOccurred(env);
	if (exception != NULL){
		//讓Java程式碼可以繼續執行
		//清空異常資訊
		(*env)->ExceptionClear(env);

		//補救措施
		fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
	}

	//獲取屬性的值
	jstring jstr = (*env)->GetObjectField(env, jobj, fid);
	char *str = (*env)->GetStringUTFChars(env, jstr, NULL);

	//對比屬性值是否合法
	if (_stricmp(str, "xiaoming2") != 0){
		//認為丟擲異常,給Java層處理
		jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
		(*env)->ThrowNew(env, newExcCls, "key's value is invalid!");
	}
}
複製程式碼

執行結果.png

關於更加詳細的異常處理,大家可以參考這篇文章:《JNI/NDK開發指南(十一)——JNI異常處理

快取策略

區域性變數使用static jfieldID key_id

Java類:

public class MyException {
	
	public native void cached();
	
	private String name = "xiaoming";
	
	public static void main(String[] args) {
		MyException m = new MyException();
		for(int i = 0;i< 10;i++) {
			m.cached();
		}
	}
	
	//載入動態庫
	static {
		System.loadLibrary("ConsoleApplication1");
	}

}
複製程式碼

native實現

JNIEXPORT void JNICALL Java_com_lwj_test_MyException_cached
(JNIEnv *env, jobject jobj){
	jclass cls = (*env)->GetObjectClass(env, jobj);
	//獲取jfieldID只獲取一次
	//區域性靜態變數
	static jfieldID key_id = NULL;
	if (key_id == NULL){
		key_id = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
		printf("--------GetFieldID-------\n");
	}
}
複製程式碼

執行結果.png

從結果中看出只獲取一次。

2、全域性變數

//初始化全域性變數,動態庫載入完成之後,立刻快取起來
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_initIds(JNIEnv *env, jclass jcls){	
	key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;");
	random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I");
}
複製程式碼

相關文章