`
李楚男
  • 浏览: 118492 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

如何在android的jni线程中实现回调

 
阅读更多
如何在android的jni线程中实现回调
分类: C/C++ Android 2012-03-16 11:38 711人阅读 评论(2) 收藏 举报

JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。

其中一种在Android系统的解决方案是:

把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。


假设有c++函数:

[cpp] view plaincopy

    void *thread_entry(void *args) 
    { 
        while(1) 
        { 
            printf("thread running...\n"); 
            sleep(1); 
        } 
         
         
    } 
     
    void init() 
    {    
        pthread_t thread; 
        pthread_create(&thread,NULL,thread_entry,(void *)NULL); 
    } 


init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive:

[cpp] view plaincopy

    public void Receive(char buffer[],int length){ 
            String msg = new String(buffer); 
            msg = "received from jni callback:" + msg; 
            Log.d("Test", msg); 
    } 


首先在c++中定义回调函数指针:

[cpp] view plaincopy

    //test.h 
    #include <pthread.h> 
    //function type for receiving data from native 
    typedef void (*ReceiveCallback)(unsigned char *buf, int len); 
     
    /** Callback for creating a thread that can call into the Java framework code.
     *  This must be used to create any threads that report events up to the framework.
     */ 
    typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg); 
     
    typedef struct{ 
        ReceiveCallback recv_cb; 
        CreateThreadCallback create_thread_cb; 
    }Callback; 


再修改c++中的init和thread_entry函数:

[cpp] view plaincopy

    //test.c 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <pthread.h> 
    #include <sys/wait.h> 
    #include <unistd.h> 
    #include "test.h" 
     
    void *thread_entry(void *args) 
    { 
        char *str = "i'm happy now"; 
        Callback cb = NULL; 
        int len; 
        if(args != NULL){ 
            cb = (Callback *)args;   
        } 
         
        len = strlen(str); 
        while(1) 
        { 
            printf("thread running...\n"); 
            //invoke callback method to java 
            if(cb != NULL && cb->recv_cb != NULL){ 
                cb->recv_cb((unsigned char*)str, len); 
            } 
            sleep(1); 
        } 
         
         
    } 
     
    void init(Callback *cb) 
    {    
        pthread_t thread; 
        //pthread_create(&thread,NULL,thread_entry,(void *)NULL); 
        if(cb != NULL && cb->create_thread_cb != NULL) 
        { 
            cb->create_thread_cb("thread",thread_entry,(void *)cb); 
        } 
    } 


然后在jni中实现回调函数,以及其他实现:
[cpp] view plaincopy

    //jni_test.c 
    #include <stdlib.h> 
    #include <malloc.h> 
    #include <jni.h> 
    #include <JNIHelp.h> 
    #include "android_runtime/AndroidRuntime.h" 
     
    #include "test.h" 
    #define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test" 
     
     
    using namespace android; 
     
     
    static jobject mCallbacksObj = NULL; 
    static jmethodID method_receive; 
     
     
     
    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { 
        if (env->ExceptionCheck()) { 
            LOGE("An exception was thrown by callback '%s'.", methodName); 
            LOGE_EX(env); 
            env->ExceptionClear(); 
        } 
    } 
     
     
     
    static void receive_callback(unsigned char *buf, int len) 
    { 
        int i; 
        JNIEnv* env = AndroidRuntime::getJNIEnv(); 
        jcharArray array = env->NewCharArray(len); 
        jchar *pArray ; 
         
        if(array == NULL){ 
            LOGE("receive_callback: NewCharArray error."); 
            return;  
        } 
     
        pArray = (jchar*)calloc(len, sizeof(jchar)); 
        if(pArray == NULL){ 
            LOGE("receive_callback: calloc error."); 
            return;  
        } 
     
        //copy buffer to jchar array 
        for(i = 0; i < len; i++) 
        { 
            *(pArray + i) = *(buf + i); 
        } 
        //copy buffer to jcharArray 
        env->SetCharArrayRegion(array,0,len,pArray); 
        //invoke java callback method 
        env->CallVoidMethod(mCallbacksObj, method_receive,array,len); 
        //release resource 
        env->DeleteLocalRef(array); 
        free(pArray); 
        pArray = NULL; 
         
        checkAndClearExceptionFromCallback(env, __FUNCTION__); 
    } 
     
    static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg) 
    { 
        return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg); 
    } 
     
    static Callback mCallbacks = { 
        receive_callback, 
        create_thread_callback 
    }; 
     
     
     
    static void jni_class_init_native 
    (JNIEnv* env, jclass clazz) 
    { 
        method_receive = env->GetMethodID(clazz, "Receive", "([CI)V"); 
    } 
     
    static int jni_init 
    (JNIEnv *env, jobject obj) 
    { 
     
         
        if (!mCallbacksObj) 
            mCallbacksObj = env->NewGlobalRef(obj); 
         
        return init(&mCallbacks); 
    } 
     
    static const JNINativeMethod gMethods[] = {   
        { "class_init_native",          "()V",          (void *)jni_class_init_native }, 
        { "native_init",                "()I",          (void *)jni_init }, 
    };   
     
     
     
    static int registerMethods(JNIEnv* env) {   
     
     
        const char* const kClassName = RADIO_PROVIDER_CLASS_NAME; 
        jclass clazz;    
        /* look up the class */   
        clazz = env->FindClass(kClassName);   
        if (clazz == NULL) {   
            LOGE("Can't find class %s/n", kClassName);   
            return -1;   
        }   
        /* register all the methods */   
        if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)   
        {   
            LOGE("Failed registering methods for %s/n", kClassName);   
            return -1;   
        }   
        /* fill out the rest of the ID cache */   
        return 0;   
    }    
     
     
    jint JNI_OnLoad(JavaVM* vm, void* reserved) {  
        JNIEnv* env = NULL;   
        jint result = -1;   
        LOGI("Radio JNI_OnLoad");   
            if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {   
            LOGE("ERROR: GetEnv failed/n");   
            goto fail;   
        }   
     
        if(env == NULL){ 
            goto fail; 
        } 
        if (registerMethods(env) != 0) {  
            LOGE("ERROR: PlatformLibrary native registration failed/n");   
            goto fail;   
        }   
        /* success -- return valid version number */       
        result = JNI_VERSION_1_4;   
    fail:   
        return result;   
    }  


jni的Android.mk文件中共享库设置为:

[cpp] view plaincopy

    LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper 


最后再实现Java中的Test类:

[java] view plaincopy

    //com.tonny.Test.java 
     
    public class Test { 
     
        static{ 
            try { 
                System.loadLibrary("test"); 
                class_init_native(); 
                 
            } catch(UnsatisfiedLinkError ule){ 
                System.err.println("WARNING: Could not load library libtest.so!"); 
            } 
             
        } 
         
         
     
        public int initialize() { 
            return native_radio_init(); 
        } 
     
        public void Receive(char buffer[],int length){ 
            String msg = new String(buffer); 
            msg = "received from jni callback" + msg; 
            Log.d("Test", msg); 
        } 
         
         
         
        protected  static native void class_init_native(); 
         
        protected  native int native_init(); 
     
    } 
分享到:
评论

相关推荐

    Android JNI多线程编程回调JAVA函数

    本话题将深入探讨如何在Android中使用JNI进行多线程编程,并实现native方法对Java函数的回调。 1. **JNI基础知识**: - JNI是Java平台的一部分,为Java应用程序提供了与本地代码交互的能力。开发者可以通过JNI在...

    android jni多线程回调

    JNI调用比较简单,根据JNI给出的实例,本内容主要讲多线程使用回调步骤:主要说明参照我的博文 http://blog.csdn.net/inr12345/article/details/8935350

    轻松学会JNI层多线程回调java方法

    多线程回调Java方法在JNI层实现,能够帮助我们优化程序执行效率,特别是在处理耗时操作如图像处理、音频视频解码等场景。 本文将深入探讨如何在JNI层实现多线程回调Java方法,以及如何解决在C/C++层多线程环境下...

    JNI层创建的线程中回调java方法

    在Android开发中,JNI(Java Native Interface)是一个关键的技术,它允许...通过分析和学习这个示例,你可以更好地理解JNI线程回调的实现细节。在实际项目中,理解并掌握这些知识对于提高程序的性能和稳定性至关重要。

    JniCallback.zip_Android jni_android_jni android_jni callback_jni

    “JniCallback.zip”中的“JniCallback”文件可能是一个示例项目,展示了如何在Android应用中实现JNI回调。这个项目可能包含了一个Java类,该类定义了回调接口,以及对应的本地代码实现,演示了如何在本地代码中...

    android jni c回调java

    本教程将详细介绍如何在Android中使用JNI实现C语言回调Java的方法,包括有参无参、有无返回值以及静态非静态函数的不同情况。 1. **JNI基础概念** JNI是Java平台的标准组成部分,它提供了一套接口,使得Java代码...

    jni中用多线程调用java代码

    例如,你可以创建一个方法来启动一个新的线程,并传入一个回调函数,这个函数将在新线程中被调用。 2. **生成JNI头文件**:使用`javah`工具(或者在Android Studio中自动完成)根据你的Java类生成对应的C/C++头文件...

    jni的回调使用

    JNI(Java Native Interface)是Java平台提供的一种标准接口,它允许Java代码和其他语言写的代码进行交互。...在实际应用中,合理运用JNI回调可以提高性能,实现复杂功能,但也需要注意其带来的额外复杂性。

    JNI 回调函数 Callback

    综上所述,JNI回调函数Callback是Android开发中连接Java和C/C++的重要方式,它使得两个世界之间的通信更为灵活,能够实现更多复杂的逻辑。在实际应用中,开发者需要熟练掌握JNI的基础知识,并了解如何安全有效地使用...

    android jni使用curl进行http请求和文件下载

    在Android开发中,JNI(Java Native Interface)是一种技术,允许Java代码和其他编程语言(如C++)进行交互。JNI在很多场景下都很有用,比如优化性能、调用系统底层库或者像本例中那样,利用C/C++库来实现特定功能。...

    android jni 里面使用NewGlobalRef

    例如,如果你有一个线程或者回调需要长期保留Java对象,全局引用就非常有用。 创建全局引用的步骤如下: 1. 首先,你需要一个对Java对象的本地引用,通常通过`env-&gt;GetObjectField`或`env-&gt;CallObjectMethod`等...

    hello-jniCallback_jni_android_

    "hello-jniCallback"是一个常见的示例项目,用于演示如何在Android应用中使用JNI来调用C/C++代码,并实现回调机制。这个项目可以帮助开发者理解JNI的基本用法以及如何在Java和原生代码之间传递数据。 1. **JNI基础...

    android JNI串口驱动支持多串口同时收发

    如果选择异步回调,那么在C/C++库中设置事件监听,并通过JNI回调Java层的函数,通知Java应用有新的数据可读或发送完成。 在描述中提到的`serial`文件可能包含了实现这些功能的源代码,如`SerialPort.c`或`...

    Android JNI开发Demo

    Android JNI(Java Native Interface)开发是将Java代码与C/C++原生代码集成的一种技术,它允许开发者在Android应用中利用C/C++的高性能和低级别控制能力。本Demo是基于实际项目经验的总结,旨在展示JNI的核心用法和...

    Android JNI Demo

    总结起来,"Android JNI Demo"是一个实践教程,旨在教会开发者如何在Android应用中使用JNI技术,结合C/C++代码提高应用性能,调用本地库,以及实现更复杂的计算任务。通过这个示例,开发者可以深入理解JNI的工作原理...

    jni.rar_Android jni_JAVA串口 JNI_android_android RS232_jni

    同时,为了保证线程安全,通常会使用线程或异步回调来处理串口的读写操作。 7. **数据传输**:通过JNI的`writeDataToSerialPort()`函数,可以将Java层的数据转换为字节流并发送到串口;而`readDataFromSerialPort()...

    JNI教程大全集,android开发必看!绝对经典!

    5. **线程安全**:由于Java和C/C++的线程模型不同,因此在JNI编程中需要特别注意线程同步问题。教程会介绍如何在本地代码中正确地管理和同步Java对象。 6. **回调机制**:JNI支持Java方法回调到本地代码,这对于...

    Android JNI native调用 java层demo TESTJNI.zip

    本文将深入探讨在Android中如何使用JNI,特别是如何从C++ native代码调用Java层的类、方法、属性以及接口,同时涉及线程回调接口的实现。 首先,我们需要了解JNI的基本结构。一个典型的JNI应用会包含Java源文件、C/...

    Android NDK开发——C回调Java中的方法

    本篇文章将详细介绍如何在Android NDK开发中实现C回调Java中的方法。 首先,了解NDK和JNI的基础概念是必要的。NDK是一套工具,提供了在Android平台上编译和运行C/C++代码的环境。而JNI是Java平台的标准接口,它允许...

Global site tag (gtag.js) - Google Analytics