很多场合都有这样的需求,由于以前都是java调用c的接口,没有做过回调,今天花了大半天时间把这个流程跑通了,记录一下,以备后用。这里发句牢骚,那些网上分享出来的代码,请问你们确实是能正常工作吗?还有查来查去都是那几份,大家转载精神可嘉啊
jni相关头文件代码
/* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class com_example_ndktest_CallbackTest */ #ifndef _Included_com_example_ndktest_CallbackTest #define _Included_com_example_ndktest_CallbackTest #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_ndktest_CallbackTest * Method: start * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_ndktest_CallbackTest_start (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
具体实现代码
#include<stdlib.h> #include<pthread.h> #include<jni.h> #include<android/log.h> #include "com_example_ndktest_CallbackTest.h" #define LOG_TAG "jni" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) jmethodID mid; jclass objclass; jobject mobj; pthread_t thread; JavaVM *m_vm; //初始化的时候会调进来一次,在这个方法里持有jvm的引用 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){ m_vm=vm; JNIEnv* env = NULL; jint result = -1; if(m_vm){ LOGD("m_vm init success"); }else{ LOGD("m_vm init failed"); } if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK){ return result; } return JNI_VERSION_1_4; } JNIEnv* getJNIEnv(int* needsDetach){ JNIEnv* env = NULL; jint result = -1; if ((*m_vm)->GetEnv(m_vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK){ int status = (*m_vm)->AttachCurrentThread(m_vm, &env, 0); if (status < 0){ LOGD("failed to attach current thread"); return NULL; } *needsDetach = 1; } LOGD("GetEnv Success"); return env; } void *thread_run(){ LOGD("thread start"); int needsDetach; JNIEnv *evn=getJNIEnv(&needsDetach); LOGD("start noop callback"); int i; for(i = 0; i < 100; i++){ jstring jstr = (*evn) -> NewStringUTF(evn, "I am Fengfei"); LOGD("invoke callback"); (*evn)->CallVoidMethod(evn, mobj, mid, jstr); jthrowable exception = (*evn)->ExceptionOccurred(evn); if (exception) { (*evn)->ExceptionDescribe(evn); } sleep(2); } if(needsDetach) (*m_vm)->DetachCurrentThread(m_vm); } JNIEXPORT void JNICALL Java_com_example_ndktest_CallbackTest_start(JNIEnv *evn, jobject object){ LOGD("call start"); //在子线程中不能这样用 //jclass tclass = (*evn)->FindClass(evn, "com/example/ndktest/CallbackTest"); //这种写法可以用在子线程中 objclass=(*evn)->GetObjectClass(evn, object); mid = (*evn)->GetMethodID(evn, objclass, "callback", "(Ljava/lang/String;)V"); //JNI 函数参数中 jobject 或者它的子类,其参数都是 local reference。Local reference 只在这个 JNI函数中有效,JNI函数返回后,引用的对象就被释放,它的生命周期就结束了。若要留着日后使用,则需根据这个 local reference 创建 global reference。Global reference 不会被系统自动释放,它仅当被程序明确调用 DeleteGlobalReference 时才被回收。(JNI多线程机制) mobj=(*evn)->NewGlobalRef(evn, object); pthread_create(&thread, NULL, thread_run, NULL); }
java代码(具体怎么生成.so,参看android ndk使用)
package com.example.ndktest; public class CallbackTest { static { System.loadLibrary("callback"); } public native void start(); public void callback(String str){ System.out.println(str); } }
时间: 2024-11-10 07:04:43