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.
Update
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)