JNI學習二之(C原始碼中Log輸出及常見錯誤)
阿新 • • 發佈:2019-02-06
瞭解jni
JNI 即Java Native Interface ,Java本機介面。可以實現Java和C/C++之間的相互呼叫。
為什麼使用JNI?
擴充套件了Java虛擬機器的能力,C語言可以進行驅動開發,比如wifi共享熱點的驅動
Native code執行效率比較快,數學運算,實時渲染遊戲,音視訊處理等。Java的記憶體回收是基於演算法的,不受程式設計師的控制,而C語言的記憶體回收由程式設計師負責。
C語言產生於上世紀70年代,有很多可以複用的庫,比如ffmpeg(音視訊解碼),opencv(影象處理),opencore(音訊處理)等。
jni開發常見錯誤
- 忘記方法的引數
- java.lang.UnsatisfiedLinkError: Native method not found
一般是c中的方法名寫的不正確 - 一般沒有日誌列印 直接報錯工程停止 ,一般c程式碼有執行錯誤
- 引用別人.so 函式庫 ,需要你自己native方法對應類的包名和別人打包成.so函式庫的包名一致
在C原始碼中輸出log
我們知道需要的jni.h檔案在ndk目錄的如下目,其中android 平臺的版本可任選
ndk-bundle\platforms\android-23\arch-arm\usr\include\jni.h
而關於log輸出的標頭檔案放在\include\android目錄下,即log.h
#ifndef _ANDROID_LOG_H
#define _ANDROID_LOG_H
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Android log priority values, in ascending priority order.
*/
//Log優先順序
typedef enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
ANDROID_LOG_VERBOSE,//v
ANDROID_LOG_DEBUG,//d
ANDROID_LOG_INFO,//i
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;
/*
* Send a simple string to the log.
*/
int __android_log_write(int prio, const char *tag, const char *text);
/*
* Send a formatted string to the log, used like printf(fmt,...)
*/
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
#if defined(__GNUC__)
__attribute__ ((format(printf, 3, 4)))
#endif
;
/*
* A variant of __android_log_print() that takes a va_list to list
* additional parameters.
*/
int __android_log_vprint(int prio, const char *tag,
const char *fmt, va_list ap);
/*
* Log an assertion failure and SIGTRAP the process to have a chance
* to inspect it, if a debugger is attached. This uses the FATAL priority.
*/
void __android_log_assert(const char *cond, const char *tag,
const char *fmt, ...)
#if defined(__GNUC__)
__attribute__ ((noreturn))
__attribute__ ((format(printf, 3, 4)))
#endif
;
#ifdef __cplusplus
}
#endif
#endif /* _ANDROID_LOG_H */
其中關於輸出log的兩個函式時:
//prio優先順序 tag和即標籤
int __android_log_write(int prio, const char *tag, const char *text);
int __android_log_print(int prio, const char *tag, const char *fmt, ...);
這兩個方法沒什麼大的區別,關鍵就在於第二個方法是可以傳入可變引數,比較靈活,其中…代表可變引數。就像printf函式那樣。
但是這連個函式的名字太長了,寫起來不太方便,我們就定義巨集來使用。
#include "com_pngfi_jnidemo_MainActivity.h"
#include <android/log.h>
#define TAG "clog"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__)
JNIEXPORT jstring Java_com_pngfi_jnidemo_MainActivity_hello(JNIEnv *env, jobject obj) {
int x=100;
int y=105;
LOGI("log in c %s %d","info",x);
LOGD("log in c %s %d","debug",y);
return (*(*env)).NewStringUTF(env, "hello jni");
}
這時候首先要匯入log.h標頭檔案,然後還需要引入庫,以前是在Android.mk檔案中新增,現在我們自己沒有寫.mk檔案,是讓AndroidStudio幫我們生成。那我們同樣需要在build.gradle檔案中defaultConfigs節點配置
//其中ldLibs 就是引入所需的庫
ndk {
moduleName "JniDemo"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
輸出結果如下: