I have a separate thread running in C++ in the background and I want it to be able to post code to be run on another thread that's already running an android.os.Looper (e.g. the main thread). By 'post', I mean something akin to View#post
where a Runnable
is enqueued to be run on the event loop. The code that would be executed is also written in C++.
I found the ALooper API (http://developer.android.com/ndk/reference/group___looper.html), but the docs aren't great and it's unclear to me whether getting the ALooper associated with the destination thread, adding another FD, and signaling it will make my code maintain correct ordering in the event queue with respect to the other enqueued Runnables.
I'd prefer not to have to go through Java and get a Handler, etc. -- it just seems unnecessary since both the code I'm trying to run and the code that's posting it are in c++.
A condensed code block is as follows: new Handler(Looper. getMainLooper()). post(new Runnable() { @Override public void run() { // things to do on the main thread } });
Caution: A service runs in the main thread of its hosting process; the service does not create its own thread and does not run in a separate process unless you specify otherwise. You should run any blocking operations on a separate thread within the service to avoid Application Not Responding (ANR) errors.
Main Thread: The default, primary thread created anytime an Android application is launched. Also known as a UI thread, it is in charge of handling all user interface and activities, unless otherwise specified. Runnable is an interface meant to handle sharing code between threads. It contains only one method: run() .
A thread can only have one Looper associated with it, a Looper has only one message queue, so mixing Java and native callbacks will maintain ordering.
With that, I don't think there is any contractual obligation in Android today that post()
is guaranteed to execute in particular order, i.e.
getHandler().post(new Runnable() { @Override public void run() { mTextView.setText("first"); } }); getHandler().post(new Runnable() { @Override public void run() { mTextView.setText("second"); } });
is not formally guaranteed to leave mTextView displaying second. Definitely nothing is set in stone when two posts are issued from different threads, or delayed.
You can find an Android messaging and concurrency framework for native code development desctibed in a great blog post.
Here is the required proof. The stacktrace below was received while working on an unrelated problem:
A/art: art/runtime/check_jni.cc:65] native: #00 pc 0000484c /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23) A/art: art/runtime/check_jni.cc:65] native: #01 pc 00003031 /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8) A/art: art/runtime/check_jni.cc:65] native: #02 pc 002441f9 /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::mirror::ArtMethod*)+68) A/art: art/runtime/check_jni.cc:65] native: #03 pc 002285a1 /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+144) A/art: art/runtime/check_jni.cc:65] native: #04 pc 000afe9b /system/lib/libart.so (art::JniAbort(char const*, char const*)+582) A/art: art/runtime/check_jni.cc:65] native: #05 pc 000b05d1 /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+60) A/art: art/runtime/check_jni.cc:65] native: #06 pc 000b299d /system/lib/libart.so (art::ScopedCheck::Check(bool, char const*, ...) (.constprop.129)+672) A/art: art/runtime/check_jni.cc:65] native: #07 pc 000bab87 /system/lib/libart.so (art::CheckJNI::CallVoidMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+50) A/art: art/runtime/check_jni.cc:65] native: #08 pc 00060817 /system/lib/libandroid_runtime.so (???) A/art: art/runtime/check_jni.cc:65] native: #09 pc 000a5b29 /system/lib/libandroid_runtime.so (???) A/art: art/runtime/check_jni.cc:65] native: #10 pc 00010fd7 /system/lib/libutils.so (android::Looper::pollInner(int)+482) A/art: art/runtime/check_jni.cc:65] native: #11 pc 00011081 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+92) A/art: art/runtime/check_jni.cc:65] native: #12 pc 0007fbe5 /system/lib/libandroid_runtime.so (android::NativeMessageQueue::pollOnce(_JNIEnv*, int)+22) A/art: art/runtime/check_jni.cc:65] native: #13 pc 00051b8b /system/framework/arm/boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+102) A/art: art/runtime/check_jni.cc:65] at android.os.MessageQueue.nativePollOnce(Native method) A/art: art/runtime/check_jni.cc:65] at android.os.MessageQueue.next(MessageQueue.java:143) A/art: art/runtime/check_jni.cc:65] at android.os.Looper.loop(Looper.java:122) A/art: art/runtime/check_jni.cc:65] at android.app.ActivityThread.main(ActivityThread.java:5411) A/art: art/runtime/check_jni.cc:65] at java.lang.reflect.Method.invoke!(Native method) A/art: art/runtime/check_jni.cc:65] at java.lang.reflect.Method.invoke(Method.java:372) A/art: art/runtime/check_jni.cc:65] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:916) A/art: art/runtime/check_jni.cc:65] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:709)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With