2011-09-10 81 views
5

我一直在閱讀很多關於線程,處理程序,loopers等,我很困惑。在我的應用程序中,我想讓第一個Activity啓動一個後臺工作器。這個後臺工作人員將不斷請求來自TCP套接字的數據,並且(希望)在數據到達時將新信息發佈到UI線程。如果用戶轉換到新的Activity,背景需要繼續做這件事,但只發送不同的消息到UI線程,以便它可以相應地更新新的佈局。Android:正確的方式將消息從後臺線程傳遞到UI線程?

這裏是我迄今爲止...這是在另一個文件中定義我我的背景工作者線程像這樣我的主要活動文件

public class MyTCPTest extends Activity { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // set the layout 
     setContentView(R.layout.main); 
     // create a handler to handle messages from bg thread 
     Handler handler = new Handler(); 

     BgWorkerThread bgw = new BgWorkerThread(); 
     bgw.start(); 
} 

...

public class BgWorkerThread extends Thread {  
@Override 
public void run(){ 

    while(true) 
    { 
     try { 
     // simulate a delay (send request for data, receive and interpret response) 
     sleep(1000); 

        // How do I send data here to the UI thread? 

     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

如果UI切換到不同的Activity會使這個線程繼續運行?另外,該線程如何知道將消息發送到哪個活動?顯然,我希望它始終將數據發送到當前活動的活動。這是否會自動發生?

最後,當UI切換到不同的活動時,需要通知bgworker,以便它可以開始請求與新的活動佈局相關的數據。告知員工這一變化的最佳方式是什麼?我不能只在BgWorkerThread類中創建一個可以在活動加載時調用的公共方法嗎?

回答

1

我認爲你正在尋找一個UI回調機制。我在這裏回答了一個類似的問題:Best way to perform an action periodically [while an app is running] - Handler?。如您所見,我通過創建Handler實例,然後調用sendEmptyMessage(),從後臺線程向UI發送消息。還有其他類型的消息可以發送,但這是一個微不足道的例子。

希望有所幫助。

+0

特拉維斯感謝您的鏈接,但我仍然感到困惑。不同的是,你的所有代碼似乎都在同一個類中。我的後臺工作人員是它自己的類,擴展線程。這是一個獨立於Activity類的類,因此如何訪問該類/活動的處理程序? – PICyourBrain

3

我已經在以下SO Question中說明了相同的代碼和更詳細的步驟。總之,爲了通知您的用戶界面並給出不同的上下文,我建議如下:

  • 有一張映射,它將requestId映射到Handler(假設您擁有請求ID的上下文)。您可以在活動中註冊適當的處理程序,因此您可以讓處理程序對每個活動有不同的行爲(例如,當它從服務器接收到響應時更新各種UI元素)
  • 更改爲線程模型的AsyncTask,因爲它具有onProgressUpdate方法它易於編碼,以便從後臺線程

這裏通知UI線程是您BackgroundThread

public class ResponseHandler extends AsyncTask<Void, String, Integer> { 
    boolean isConnectionClosed = false; 
    Map<Integer, Handler> requestIdToMapHandler; 

    public ResponseHandler() { 
     this.requestIdToMapHandler = new HashMap<Integer, Handler>(); 
    } 

    @Override 
    protected Integer doInBackground(Void... params) { 
     int errorCode = 0; 

     try { 
      // while not connection is not close 
      while(!isConnectionClosed){ 
       // blocking call from the device/server 
       String responseData = getResponse(); 

       // once you get the data, you publish the progress 
       // this would be executed in the UI Thread 
       publishProgress(responseData); 
      } 
     } catch(Exception e) { 
      // error handling code that assigns appropriate error code 
     } 

     return errorCode; 

    } 

    @Override 
    protected void onPostExecute(Integer errorCode) { 
     // handle error on UI Thread 
    } 

    @Override 
    protected void onProgressUpdate(String... values) { 
     super.onProgressUpdate(values); 
     String responseData = values[0]; 

     // the response contains the requestId that we need to extract 
     int requestId = extractId(responseData); 

     // next use the requestId to get the appropriate handler 
     Handler uiHandler = getUIHandler(requestId); 

     // send the message with data, note that this is just the illustration 
     // your data not necessary be jut String 
     Message message = uiHandler.obtainMessage(); 
     message.obj = responseData; 
     uiHandler.sendMessage(message); 
    } 

    /*** 
    * Stub code for illustration only 
    * Get the handler from the Map of requestId map to a Handler that you register from the UI 
    * @param requestId Request id that is mapped to a particular handler 
    * @return 
    */ 
    private Handler getUIHandler(int requestId) { 
     return null; 
    } 

    /*** 
    * Stub code for illustration only, parse the response and get the request Id 
    * @param responseId 
    * @return 
    */ 
    private int extractId(String responseId) { 
     return 0; 
    } 

    /*** 
    * Stub code for illustration only 
    * Call the server to get the TCP data. This is a blocking socket call that wait 
    * for the server response 
    * @return 
    */ 
    private String getResponse() { 
     return null; 
    } 
} 
0

存根/僞代碼可以使用

runOnUIThread(new Runnable { 

public void run() { 
//Update your UI here like update text view or imageview etc 

} 

});