Android JNI - Call function on Android UI thread from C++

后端 未结 4 1716
醉梦人生
醉梦人生 2020-12-08 17:51

Our game engine Cocos2d-x runs natively on android on its own non-Java-UI-thread. We need to call certain Java functions from C++ via

4条回答
  •  -上瘾入骨i
    2020-12-08 17:58

    As @Elviss has mentioned - to post your code to main thread you should use Looper. Actually this may be done without extra coping with JNI and creating of custom java.lang.Runnable and posting it via complicated JNI stuff.

    Android NDK offers extremely lightweight and efficient way to post your native code to the arbitrary looper. The key point is that you should provide arbitrary file descriptor to the looper and specify what file events you are interested in (input, output, so on). Under the hood looper will poll that file descriptor and once event becomes available - it runs your callback on proper thread.

    There is the minimal example (no error checks and teardowns):

    #include 
    #include 
    
    #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "sergik", __VA_ARGS__)
    
    static ALooper* mainThreadLooper;
    static int messagePipe[2];
    
    static int looperCallback(int fd, int events, void* data);
    
    void someJniFuncThatYouShouldCallOnceOnMainThread() {
        mainThreadLooper = ALooper_forThread(); // get looper for this thread
        ALooper_acquire(mainThreadLooper); // add reference to keep object alive
        pipe(messagePipe); //create send-receive pipe
        // listen for pipe read end, if there is something to read
        // - notify via provided callback on main thread
        ALooper_addFd(mainThreadLooper, messagePipe[0],
                      0, ALOOPER_EVENT_INPUT, looperCallback, nullptr);
        LOGI("fd is registered");    
    
        // send few messages from arbitrary thread
        std::thread worker([]() {
            for(char msg = 100; msg < 110; msg++) {
                LOGI("send message #%d", msg);
                write(messagePipe[1], &msg, 1);
                sleep(1);
            }
        });
        worker.detach();
    }
    
    // this will be called on main thread
    static int looperCallback(int fd, int events, void* data) {
        char msg;
        read(fd, &msg, 1); // read message from pipe
        LOGI("got message #%d", msg);
        return 1; // continue listening for events
    }
    

    This code produces next output:

    06-28 23:28:27.076 30930-30930/? I/sergik: fd is registered
    06-28 23:28:27.076 30930-30945/? I/sergik: send message #100
    06-28 23:28:27.089 30930-30930/? I/sergik: got message #100
    06-28 23:28:28.077 30930-30945/? I/sergik: send message #101
    06-28 23:28:28.077 30930-30930/? I/sergik: got message #101
    06-28 23:28:29.077 30930-30945/? I/sergik: send message #102
    06-28 23:28:29.078 30930-30930/? I/sergik: got message #102
    06-28 23:28:30.078 30930-30945/? I/sergik: send message #103
    06-28 23:28:30.078 30930-30930/? I/sergik: got message #103
    06-28 23:28:31.079 30930-30945/? I/sergik: send message #104
    06-28 23:28:31.079 30930-30930/? I/sergik: got message #104
    06-28 23:28:32.079 30930-30945/? I/sergik: send message #105
    06-28 23:28:32.080 30930-30930/? I/sergik: got message #105
    06-28 23:28:33.080 30930-30945/? I/sergik: send message #106
    06-28 23:28:33.080 30930-30930/? I/sergik: got message #106
    06-28 23:28:34.081 30930-30945/? I/sergik: send message #107
    06-28 23:28:34.081 30930-30930/? I/sergik: got message #107
    06-28 23:28:35.081 30930-30945/? I/sergik: send message #108
    06-28 23:28:35.082 30930-30930/? I/sergik: got message #108
    06-28 23:28:36.082 30930-30945/? I/sergik: send message #109
    06-28 23:28:36.083 30930-30930/? I/sergik: got message #109
    

    As you see from pid-tid pairs - messages are received on main thread. And of course you may send something more complicated than one-byte messages.

提交回复
热议问题