![](/img/trans.png)
[英]Kotlin (Android) - How do I post a custom event from one thread and listen for that event in the main thread?
[英]How do I post code to be run on the Android main thread from a separate thread in C++?
我有一個單獨的線程在后台運行C ++,我希望它能夠發布代碼在另一個已運行android.os.Looper的線程上運行(例如主線程)。 通過'post',我的意思是類似於View#post
,其中Runnable
被排隊以在事件循環上運行。 將要執行的代碼也是用C ++編寫的。
我找到了ALooper API( http://developer.android.com/ndk/reference/group___looper.html ),但文檔不是很好,我不清楚是否將ALooper與目標線程關聯,添加另一個FD並發信號通知它將使我的代碼在事件隊列中相對於其他排隊的Runnables保持正確的排序。
我寧願不必通過Java並獲得Handler等等 - 這似乎是不必要的,因為我正在嘗試運行的代碼和發布它的代碼都是用c ++編寫的。
一個線程只能有一個與之關聯的Looper,一個Looper只有一個消息隊列,因此混合Java和本機回調將保持排序。
有了這個,我認為今天Android中沒有任何合同義務, post()
保證按特定順序執行,即
getHandler().post(new Runnable() {
@Override
public void run() {
mTextView.setText("first");
}
});
getHandler().post(new Runnable() {
@Override
public void run() {
mTextView.setText("second");
}
});
沒有正式保證讓mTextView顯示第二個 。 當兩個帖子從不同的線程發出或延遲時,絕對沒有任何結論。
您可以在一篇精彩的博客文章中找到用於本機代碼開發的Android消息傳遞和並發框架 。
這是必需的證明。 在處理不相關的問題時收到了下面的堆棧跟蹤:
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)
您需要一個已在主線程中執行的函數。 如果你在那里調用ALooper_forThread()
或ALooper_prepare()
,你將獲得一個指向與主線程相關的looper的指針。 記得調用ALooper_acquire()
以便它可以在不同的線程之間共享。
這可以幫助您https://groups.google.com/forum/#!topic/android-ndk/v2OITtaZTes
但是通過java端的處理程序很容易實現,通過jni調用發送和處理在本機和java之間來回傳遞的消息。
你將不得不通過Java,因為android.os.Looper
沒有在本機代碼中實現 (至少在當前最近的提交中 )。
我沒有足夠的NDK經驗來快速輸入所需的樣板,但顯而易見的選擇似乎是創建一個基於本機代碼的java Runnable
並將其發送到looper。
不太明顯的解決方案是直接在線程的MessageQueue
上運行。 一旦你有了它的引用,你可以在那里注冊本機管道的一端,並將消息寫入另一端; 管道基本上具有Handler
的功能,但在本機代碼上。 從技術上講,您的代碼仍然是從Java調用的,但您不需要開銷。 我沒有找到關於整個事情的大量文檔,但這個帖子可能是一個很好的起點.¹
但是,完全有可能實際上不必從主線程調用您的代碼,或者有其他選項可以在不通過Java的情況下解決您的問題。 然而,這將取決於您試圖解決的問題。
注意:我假設主線程場景。 如果您可以在要部署的線程中使用基於本機代碼的循環器,則可以使用更多選項。
¹也可以在某種客戶端模式下使用ALooper
來實現這一點。 對此非常不確定。
如果你想從另一個線程在主線程中創建一些東西,我建議你使用runOnUiThread函數。 Android中的主要線程是用戶界面線程。 我不確定你是否可以在ndk代碼中使用這個功能。
代碼示例可能是這樣的:
private void runOnMainThread(){
runOnUiThread(new Runnable(){ public void run() { try { // do some stuffs } catch (final Exception ex) { // handle the possible exception } } }); }
無論如何,我建議你閱讀以下鏈接: link1 , link2 , link3 。
我希望它有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.