2010-05-04 94 views
1

我正在嘗試創建一個簡單的多人遊戲。有一個WorkerService這是應該處理所有的網絡通信和這項服務和我的活動之間的所有交互都與AIDL完成。我認爲這是一種標準方法 - 爲了實現雙向交互,我還使用了一個接口(也稱爲AIDL)。從另一個線程回調導致異常

問題是,回調必須改變UI中的事情,這可能只在UI線程中完成。我創建了一個Handler(在UI線程中)並相信這是一個明顯的解決方案。但是,令人驚訝的是,它不起作用。

我的LoungeActivity調用startServer()方法IWorker接口。我的WorkerService對應的方法做了一些工作,並作出回調 - 這工作正常。然後WorkerService產卵從一個糟糕的異常此線程結果一個新線程,回調被拋出:

Can't create handler inside thread that has not called Looper.prepare()

下面是一些代碼,使其明確:

startServer()實現:

private void startServerImpl(String name, float latStart, float latEnd, 
float lonStart, float lonEnd) 
{ 
    // some instructions here 

    // this works fine: 
    callback.notifySocketCreated(); 

    // my naughty thread: 
    new ServerThread().start(); 

    // some instructions here 
} 

ServerThread code:

​​

每個方法從callback看起來像這樣:

public void notifyGameRegistered() throws RemoteException 
{ 
    handler.dispatchMessage(handler.obtainMessage(CALLBACK_GAME_REGISTERED)); 
} 

在處理器的handleMessage()方法我做一個簡單的switch(msg.what),並在任何情況下有一個簡單的UI修改(顯示舉杯,改變文本等)。

我不知道爲什麼這個異常拋出..我已經設法通過將代碼包裝到Runnable並調用runOnUiThread()來解決它,但它仍然讓我好奇 - 不應該總是在創建它的線程中運行處理程序?或者,也許我做錯了什麼?

回答

0

你必須以某種方式從主線程調用有問題的函數。

+0

那麼..我現在就這樣做。但爲什麼handleMessage在兩個不同的線程中執行?一旦它在UI(notifySocketCreated())和另一個不在(notifyGameRegistered())中。 – omarcin 2010-05-04 22:35:11

0

更改UI的功能應位於擁有UI的活動中。

這個鏈接應該幫助你: http://android-developers.blogspot.com/2009/05/painless-threading.html

+0

哦,我忘了提及。該方法也應該從擁有UI – Sid 2010-10-01 19:30:19

+0

的活動中調用。感謝您的鏈接,但我之前已經看到它。我相信AsyncTask在描述的情況下會是一種矯枉過正的行爲。對我來說,找出如何修復我的代碼並不重要(我記得在Runnables中的包裝代碼有幫助),但我很好奇爲什麼一個Handler實例曾經在UI線程中,而另一次則不是。文檔說「每個Handler實例都與單個線程和該線程的消息隊列相關聯。」... – omarcin 2010-10-02 13:13:55

1

我知道這是有點晚 - 但問題是,你叫dispatchMessage()

正確的方法是sendMessage()

dispatchMessage()將在同一個線程上調用handleMessage()

我猜這個問題不是你的Handler在錯誤的線程上 - 但是UI試圖在你的onHandle()方法的某個地方創建一個Handler。因爲onHandle()在錯誤的線程上被調用,所以你會得到一個異常。

/** 
* Handle system messages here. 
*/ 
public void dispatchMessage(Message msg) 
{ 
    if (msg.callback != null) { 
     handleCallback(msg); 
    } else { 
     handleMessage(msg); 
    } 
}