2010-10-12 93 views
13

在註冊回調處理程序的地方有很多Android SDK API。對於一個具體的例子,使用MediaPlayer,你可以設置一個onCompletionListener回調。這些回調會從主(UI)線程中調用嗎?如果答案是「它取決於」,那麼我正在尋找一些通用規則,以便從主線程與另一個線程調用哪些回調函數。 SDK文檔似乎沒有解釋清楚。 (也許我錯過了。)主(UI)線程是否發生回調?

重要的是要知道,因爲如果我保證主線程回調,那麼我可以跳過一些代碼中不同地方共享數據的線程同步。如果我因爲無知而被迫變得悲觀,那麼我必須編寫額外的同步塊代碼,並擔心死鎖,數據完整性和性能下降。

回答

10

Android將在其他線程上調用您的代碼的一種情況是,如果您創建通過AIDL公開的遠程服務,那麼這些AIDL方法將在活頁夾線程而不是主應用程序線程上調用。

但是,這是例外。正如其他人已經注意到的,其中絕大多數是在主應用程序線程上調用的。

+0

我試圖運行的異步操作,而在我的服務(使用'RxAndroid'),調用提供了使用'AndroidSchedulers.mainThread()'這個操作的客戶端回調。在調試時,我可以確認在主應用程序線程中調用的回調。 **然而,在調用回調之後,在主應用程序線程中,在回調(在客戶端)運行*的代碼不是**。不過,是否可以保證我的服務客戶端的回調代碼將在主應用程序線程中運行,因此他們不需要處理它? – Eido95 2016-11-21 08:09:31

+0

@ Eido95:我建議你問一個單獨的Stack Overflow問題,在這裏你可以用[mcve]詳細解釋,你關心的是什麼。 – CommonsWare 2016-11-21 12:25:28

3

根據我的經驗,這些回調總是回到非UI線程上。您是否嘗試過Activity.runOnUiThread()以確保您的代碼在UI線程上運行?您仍然可以獲得性能上的提升,因爲這段代碼需要更長的時間才能運行,但是您可以避免一些線程同步的常見問題。

+0

我面臨着類似的問題。我的數據源類(在一個單獨的模塊定義)的回調(在數據源來自的AsyncTask調用)返回的響應,我不會從那裏我發起 呼叫的地方接受任何電話。使用了使用Looper.getMainLooper()創建的處理程序,但問題仍然存在。 – 2018-02-07 07:41:32

2

通常,回調將發生在事件正在運行的線程上。如果您註冊回調並在非UI線程上開始播放內容,則回調將發生在非UI線程上。但是,Android不會自行在後臺創建新線程。

所有與UI相關的事件都必須在UI線程上發生,因此您可以確信點擊處理程序回調等將發生在UI線程上。正如Aaron C所指出的那樣,你可以使用Activity.runOnUiThread來強制事件在那裏發生。

此外,AsyncTask對於快速後臺工作可能非常有用,您需要完成一些步驟才能在uI線程上進行測試。

編輯:來自評論的示例。

public void MyWorker { 
    private OnCompleteListener onCompleteListener; 

    public void setOnCompleteListener(OnCompleteListener onCompleteListener) { 
    this.onCompleteListener = onCompleteListener; 
    } 

    public void doWork() { 
    // do lots of work here 
    onCompleteListener.onComplete(); 
    } 
} 

// somewhere in my Activity 

public void onCreate() { 
    final MyWorker worker = new MyWorker(); 
    worker.setOnCompleteListener(new OnCompleteListener() { ... }); 

    new Thread(new Runnable() { 
     public void run() { 
      worker.doWork(); 
     } 
    }).start(); 
} 

在此示例中,onComplete「回調」將從非UI線程運行。線程將在onComplete完成後退出。

+0

我不明白你描述的非UI工作情況如何。看來非UI線程將不會有UI線程會在其中運行的相同調度循環。即在UI線程中有一些代碼調用UI事件的方法,查看渲染,註冊回調。但是,如果我只是創造一些線程與延伸Runnable接口類,我認爲JVM是剛剛推出的螺紋和退出,在它沒有Android的SDK鉤子把回調在同一線程上。也許你在描述別的東西。 – 2010-10-12 22:35:30

+0

「回調」不一定涉及調度循環。假設你有一些課程做複雜的工作。它有一個setOnCompleteListener函數和一個啓動函數。在一些沒有UI的線程上,你給它一個OnCompleteListener,然後調用start。它關閉並完成它的事情,當它完成時它將調用registeredOnCompleteListener.onComplete()。這將導致您的偵聽器中的onComplete函數從運行該對象的線程中調用。 – 2010-10-12 22:49:55

+0

只是爲了正確理解你的例子:在線程1上,start()被調用。在線程2上,在run()方法中,調用setOnCompleteListener()。 onComplete方法會在線程1還是線程2中執行? – 2010-10-12 23:32:41

17

疑問時,您可以使用Log.i("TAG", Thread.currentThread().getName());,看看:)

+3

爲什麼你期待這個實驗的結果在未來的操作系統版本中是可重複的?你將如何設計實驗來挑起可能在另一個線程上被調用的情況?你需要開始有多少結果才能認爲這可能是普遍化的? – 2012-07-15 22:01:16

+0

wat ???????????? – dnkoutso 2018-01-29 08:20:54

0

類似的東西來到了,當我工作地點的API。正如我們所知,我們爲定位服務提供回調,以便我們在獲得位置後得到通知。 所以我在這個回調中做了一些事情,這些回調需要很長時間才能使用Geocoder API。

在此之前,我的印象是,這個回調將從其他線程調用,因此不會在主UI線程上執行。但我可以看到,情況並非如此。

因此,我在這個監聽器中編寫的代碼將在主線程上執行。

現在我不明白的是,他們如何能做到的是,它是通過使用standerd功能runOnUIThread() ???當您使用的WebView

1

另一個例外是。當的JavaScript調用Java函數,例如調用將不會在主線程發生

相關問題