日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android-NDK-hello-jniCallback

發布時間:2024/4/17 Android 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android-NDK-hello-jniCallback 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

項目目錄

CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)add_library(hello-jnicallback SHAREDhello-jnicallback.c)# Include libraries needed for hello-jnicallback lib target_link_libraries(hello-jnicallbackandroidlog)

hello-jnicallback.c

#include <string.h> #include <inttypes.h> #include <pthread.h> #include <jni.h> #include <android/log.h> #include <assert.h>// Android log function wrappers,對android log進行了封裝 static const char* kTAG = "hello-jniCallback"; #define LOGI(...) \((void)__android_log_print(ANDROID_LOG_INFO, kTAG, __VA_ARGS__)) #define LOGW(...) \((void)__android_log_print(ANDROID_LOG_WARN, kTAG, __VA_ARGS__)) #define LOGE(...) \((void)__android_log_print(ANDROID_LOG_ERROR, kTAG, __VA_ARGS__))// processing callback to handler class,上下文 typedef struct tick_context {JavaVM *javaVM;jclass jniHelperClz;--------->對應于JniHandlerjobject jniHelperObj;jclass mainActivityClz;------>對應于MainActivityjobject mainActivityObj;pthread_mutex_t lock;int done; } TickContext; TickContext g_ctx;/* This is a trivial JNI example where we use a native method* to return a new VM String. See the corresponding Java source* file located at:** hello-jniCallback/app/src/main/java/com/example/hellojnicallback/MainActivity.java*/ JNIEXPORT jstring JNICALL Java_com_example_hellojnicallback_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz ) {return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI "."); }/** A helper function to show how to call* java static functions JniHelper::getBuildVersion()* java non-static function JniHelper::getRuntimeMemorySize()* The trivial implementation for these functions are inside file* JniHelper.java這個展示了如何調用java的靜態方法,非靜態方法。*/ void queryRuntimeInfo(JNIEnv *env, jobject instance) {// Find out which OS we are running on. It does not matter for this app// just to demo how to call static functions.// Our java JniHelper class id and instance are initialized when this// shared lib got loaded, we just directly use them// static function does not need instance, so we just need to feed// class and method id to JNIjmethodID versionFunc = (*env)->GetStaticMethodID(env, g_ctx.jniHelperClz,"getBuildVersion", "()Ljava/lang/String;");//獲取靜態方法if (!versionFunc) {LOGE("Failed to retrieve getBuildVersion() methodID @ line %d",__LINE__);return;}jstring buildVersion = (*env)->CallStaticObjectMethod(env,g_ctx.jniHelperClz, versionFunc);//調用靜態的方法。const char *version = (*env)->GetStringUTFChars(env, buildVersion, NULL);//把jsting轉換為c類型的字符串if (!version) {LOGE("Unable to get version string @ line %d", __LINE__);return;}LOGI("Android Version - %s", version); /* 在調用 GetStringUTFChars 函數從 JVM 內部獲取一個字符串之后,JVM 內部會分配一塊新的內存,用于存儲源字符串的拷貝,以便本地代碼訪問和修改。即然有內存分配,用完之后馬上釋放是一個編程的好習慣。通過調用ReleaseStringUTFChars 函數通知 JVM 這塊內存已經不使用了,你可以清除了。注意:這兩個函數是配對使用的,用了 GetXXX 就必須調用 ReleaseXXX,而且這兩個函數的命名也有規律,除了前面的 Get 和 Release 之外,后面的都一樣。 */(*env)->ReleaseStringUTFChars(env, buildVersion, version);//釋放jstring。/*

局部引用:

JNI 函數內部創建的?jobject?對象及其子類(?jclass?、?jstring?、?jarray?等) 對象都是局部引用,它們在 JNI 函數返回后無效;

一般情況下,我們應該依賴 JVM 去自動釋放 JNI 局部引用;但下面兩種情況必須手動調用?DeleteLocalRef()?去釋放:

  • (在循環體或回調函數中)創建大量 JNI 局部引用,即使它們并不會被同時使用,因為 JVM 需要足夠的空間去跟蹤所有的 JNI 引用,所以可能會造成內存溢出或者棧溢出;

  • 如果對一個大的 Java 對象創建了 JNI 局部引用,也必須在使用完后手動釋放該引用,否則 GC 遲遲無法回收該 Java 對象也會引發內存泄漏.

全局引用:

全局引用允許你持有一個 JNI 對象更長的時間,直到你手動銷毀;但需要顯式調用?NewGlobalRef()?和?DeleteGlobalRef()?:

*/// we are called from JNI_OnLoad, so got to release LocalRef to avoid leaking(*env)->DeleteLocalRef(env, buildVersion);/*

方法簽名

?

???? 調用JNI的GetMethodID函數獲取一個jmethodID時,需要傳入一個方法名稱和方法簽名,方法名稱就是在Java中定義的方法名,方法簽名的格式為:(形參參數類型列表)返回值。

*/// Query available memory size from a non-static public function// we need use an instance of JniHelper class to call JNIjmethodID memFunc = (*env)->GetMethodID(env, g_ctx.jniHelperClz,"getRuntimeMemorySize", "()J");//獲取成員函數if (!memFunc) {LOGE("Failed to retrieve getRuntimeMemorySize() methodID @ line %d",__LINE__);return;}jlong result = (*env)->CallLongMethod(env, instance, memFunc);LOGI("Runtime free memory size: %" PRId64, result);(void)result; // silence the compiler warning }/** processing one time initialization:* Cache the javaVM into our context* Find class ID for JniHelper* Create an instance of JniHelper* Make global reference since we are using them from a native thread* Note:* All resources allocated here are never released by application* we rely on system to free all global refs when it goes away;* the pairing function JNI_OnUnload() never gets called at all.*/ /* 實現JNI中本地函數注冊有兩種方式:1.采用默認的本地函數注冊流程。2.自己重寫JNI_OnLload()函數。 當Android的VM執行到C組件(*so)里的System.loadLibrary()函數時,首先會去執行C組件里的JNI_OnLoad()函數,其用途有二*/ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env;memset(&g_ctx, 0, sizeof(g_ctx));g_ctx.javaVM = vm;if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR; // JNI version not supported.}jclass clz = (*env)->FindClass(env,"com/example/hellojnicallback/JniHandler");g_ctx.jniHelperClz = (*env)->NewGlobalRef(env, clz);----->獲取并保存獲取的java類jmethodID jniHelperCtor = (*env)->GetMethodID(env, g_ctx.jniHelperClz,"<init>", "()V");-------->獲取int的方法jobject handler = (*env)->NewObject(env, g_ctx.jniHelperClz,jniHelperCtor);----->使用獲取的init的方法,進行構造相應的對象g_ctx.jniHelperObj = (*env)->NewGlobalRef(env, handler);queryRuntimeInfo(env, g_ctx.jniHelperObj);g_ctx.done = 0;g_ctx.mainActivityObj = NULL;return JNI_VERSION_1_6; }/** A helper function to wrap java JniHelper::updateStatus(String msg)* JNI allow us to call this function via an instance even it is* private function. 發送一個Java的消息*/ void sendJavaMsg(JNIEnv *env, jobject instance,jmethodID func,const char* msg) {jstring javaMsg = (*env)->NewStringUTF(env, msg);(*env)->CallVoidMethod(env, instance, func, javaMsg);(*env)->DeleteLocalRef(env, javaMsg); }/** Main working thread function. From a pthread,* calling back to MainActivity::updateTimer() to display ticks on UI* calling back to JniHelper::updateStatus(String msg) for msg兩個callback,一個展示時鐘在UI界面上,一個回調發送消息*/ void* UpdateTicks(void* context) {TickContext *pctx = (TickContext*) context;JavaVM *javaVM = pctx->javaVM;JNIEnv *env;jint res = (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_6);if (res != JNI_OK) {res = (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);if (JNI_OK != res) {LOGE("Failed to AttachCurrentThread, ErrorCode = %d", res);return NULL;}}jmethodID statusId = (*env)->GetMethodID(env, pctx->jniHelperClz,"updateStatus","(Ljava/lang/String;)V");//獲取方法sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread status: initializing...");//發送消息正在初始化// get mainActivity updateTimer functionjmethodID timerId = (*env)->GetMethodID(env, pctx->mainActivityClz,"updateTimer", "()V");//獲取更新的的方法struct timeval beginTime, curTime, usedTime, leftTime;const struct timeval kOneSecond = {(__kernel_time_t)1,(__kernel_suseconds_t) 0};sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread status: start ticking ...");while(1) {gettimeofday(&beginTime, NULL);pthread_mutex_lock(&pctx->lock);int done = pctx->done;if (pctx->done) {pctx->done = 0;}pthread_mutex_unlock(&pctx->lock);if (done) {break;}(*env)->CallVoidMethod(env, pctx->mainActivityObj, timerId);gettimeofday(&curTime, NULL);timersub(&curTime, &beginTime, &usedTime);timersub(&kOneSecond, &usedTime, &leftTime);struct timespec sleepTime;sleepTime.tv_sec = leftTime.tv_sec;sleepTime.tv_nsec = leftTime.tv_usec * 1000;if (sleepTime.tv_sec <= 1) {nanosleep(&sleepTime, NULL);} else {sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread error: processing too long!");}}sendJavaMsg(env, pctx->jniHelperObj, statusId,"TickerThread status: ticking stopped");//發送時鐘消息(*javaVM)->DetachCurrentThread(javaVM);return context; }/** Interface to Java side to start ticks, caller is from onResume()*/ JNIEXPORT void JNICALL Java_com_example_hellojnicallback_MainActivity_startTicks(JNIEnv *env, jobject instance) {pthread_t threadInfo_;pthread_attr_t threadAttr_;pthread_attr_init(&threadAttr_);pthread_attr_setdetachstate(&threadAttr_, PTHREAD_CREATE_DETACHED);pthread_mutex_init(&g_ctx.lock, NULL);jclass clz = (*env)->GetObjectClass(env, instance);g_ctx.mainActivityClz = (*env)->NewGlobalRef(env, clz);g_ctx.mainActivityObj = (*env)->NewGlobalRef(env, instance);int result = pthread_create( &threadInfo_, &threadAttr_, UpdateTicks, &g_ctx);assert(result == 0);pthread_attr_destroy(&threadAttr_);(void)result; }/** Interface to Java side to stop ticks:* we need to hold and make sure our native thread has finished before return* for a clean shutdown. The caller is from onPause*/ JNIEXPORT void JNICALL Java_com_example_hellojnicallback_MainActivity_StopTicks(JNIEnv *env, jobject instance) {pthread_mutex_lock(&g_ctx.lock);g_ctx.done = 1;pthread_mutex_unlock(&g_ctx.lock);// waiting for ticking thread to flip the done flagstruct timespec sleepTime;memset(&sleepTime, 0, sizeof(sleepTime));sleepTime.tv_nsec = 100000000;while (g_ctx.done) {nanosleep(&sleepTime, NULL);}// release object we allocated from StartTicks() function(*env)->DeleteGlobalRef(env, g_ctx.mainActivityClz);(*env)->DeleteGlobalRef(env, g_ctx.mainActivityObj);g_ctx.mainActivityObj = NULL;g_ctx.mainActivityClz = NULL;pthread_mutex_destroy(&g_ctx.lock); }

Jnihandler.java

public class JniHandler {/** Print out status to logcat*/@Keepprivate void updateStatus(String msg) {if (msg.toLowerCase().contains("error")) {Log.e("JniHandler", "Native Err: " + msg);} else {Log.i("JniHandler", "Native Msg: " + msg);}}/** Return OS build version: a static function*/@Keepstatic public String getBuildVersion() {return Build.VERSION.RELEASE;}/** Return Java memory info*/@Keeppublic long getRuntimeMemorySize() {return Runtime.getRuntime().freeMemory();} }

MainAcitivity.java

@Keep private void updateTimer() {++second;if(second >= 60) {++minute;second -= 60;if(minute >= 60) {++hour;minute -= 60;}}runOnUiThread(new Runnable() {@Overridepublic void run() {String ticks = "" + MainActivity.this.hour + ":" +MainActivity.this.minute + ":" +MainActivity.this.second;MainActivity.this.tickView.setText(ticks);}}); } static {System.loadLibrary("hello-jnicallback"); } public native String stringFromJNI(); public native void startTicks(); public native void StopTicks();

?

總結

以上是生活随笔為你收集整理的Android-NDK-hello-jniCallback的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。