0

I'm pretty new to jni.

I need to invoke a native method from java code, which should perform a time-consuming operation asynchronously (in another thread), and at the end it should invoke a java callback. However I need this callback to be invoked in the same java thread that originated the operation. That is, the java application should be single-threaded, and all callbacks should be invoked in the context of this thread.

I've read tutorials on callback invocations, the stuff about keeping global refs to the object, getting the appropriate methodid and invoking it. I've also found stuff about how to call a java method from another thread (AttachCurrentThread), however this is not what I need. I need to make the java call within the originating thread, so the question is how do I switch to that thread?

For instance, in Win32 I'd use something like PostMessage/PostThreadMessage to invoke a code in the specified thread, assuming it runs the message-loop. There're also alternatives like QueueUserAPC which is applicable if the thread waits for events in an alertable state.

So, what are the options at my disposal? Is there a jni method for posting execution of a java method in the specified thread? Or perhaps a linux equivalent of PostThreadMessage? I can also think about workarounds within the java code, but prefer to solve this on the native side.

Thanks in advance.

valdo
  • 12,632
  • 2
  • 37
  • 67
  • 1
    How about sending a `Message` to a `Handler`, and let `handleMessage` invoke the callback? If you don't specify a `Looper` when constructing your `Handler`, the `Handler` should become associated with the application's main thread `Looper`. – Michael Aug 29 '15 at 20:42
  • @Michael - sounds reasonable, the problem is that I'm a beginner in android/java as well. I heard about `Message` and `Handler`, but didn't know how to deal with this. Will definitely check this, thanks. – valdo Aug 29 '15 at 21:04

1 Answers1

0

Please see a relevant recent discussion: How do I post code to be run on the Android main thread from a separate thread in C++?. The most interesting part is this thread in android-ndk group from 2012.

TL;NR: from JNI_OnLoad() or other call that happens early enough, and comes from the UI thread, you call

pipe2(messagePipe, O_NONBLOCK | O_CLOEXEC);
ALooper_addFd(ALooper_forThread(), messagePipe[0], 0, ALOOPER_EVENT_INPUT, handler, data);

Elsewhere you define a simple handler function:

int handler(int fd, int, void* pHandler) {
    int what = 0;
    read(fd, &what, sizeof(what));
    static_cast<MyHandler *>(pHandler)->handle(what));
    return 1;
}

Now the native version of Handler.sendEmptyMessage(), and a close analog of CWinThread::PostThreadMessage() (without wParam and lParam), could then be as simple as

MyHandler::sendEmptyMessage(int what) {
    write(messagePipe[1], &what, sizeof(what));
}
Community
  • 1
  • 1
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307