2010-01-07 57 views
11

我正在創建一個android應用程序,它必須在後臺執行web請求,然後處理接收到的數據並根據服務器響應修改用戶界面。如何在自己的線程中執行Web請求?

在後臺發佈請求和處理數據的目標是避免凍結用戶界面。但是目前我注意到用戶界面是凍結的,所以我不確定邏輯是否按照它應該的那樣工作。

這裏是這是應該發佈的請求,並在其自己的線程處理響應,然後將該數據傳遞給GUI代碼的一部分:

public class ServerConnection { 

Queue<String> requests; 

... 

DefaultHttpClient httpClient; 
HttpHost targetHost; 

Handler handler; 

ServerResponseHandler responseHandler; 
Activity activity; 

public ServerConnection(Activity activity){ 
    this.activity = activity; 
    this.responseHandler = (ServerResponseHandler) activity; 
    httpClient = new DefaultHttpClient(); 
    targetHost = new HttpHost(TARGET_DOMAIN, 80, "http"); 
    requests = new LinkedList<String>(); 
} 



private Runnable requestSender = new Runnable(){ 

    @Override 
    public void run() { 
     if(!requests.isEmpty()){ 
      String requestString = requests.remove(); 
      HttpGet httpGet = new HttpGet(requestString); 
      httpGet.addHeader("Accept", "text/xml"); 
      String encodingString = "testuser:testpass"; 
      String sEncodedString = Base64Coder.encodeString(encodingString); 

      try{ 

       String sContent = fetchURL(requestString, sEncodedString); 

       XMLParser xmlParser = new XMLParser(); 

       List <Product> products = xmlParser.getProducts(sContent); 

       responseHandler.onProductsResponse(products); 
      } 
      catch(Exception ex){ 
       Log.e(TAG, ex.getMessage()); 
      } 
     } 
    } 
}; 

public void sendRequest(String requestString){ 
    requests.add(requestString); 
    handler = new Handler(); 
    handler.post(requestSender); 
} 

方法sendRequest將()被從主活動稱爲其實現ServerResponseHandler。我猜這個請求是在它自己的線程中執行的,並且通過調用

responseHandler.onProductsResponse(products);

產品清單(來自網絡的數據)傳遞給主要活動。無論如何,由於表現不佳,如果有人能夠糾正上述邏輯中的任何可能的問題或建議任何其他(更好的)選項,我將不勝感激。

回答

21

我建議你看看ASyncTask class(從Android 1.5開始可用)。

它簡化了創建後臺線程的過程,該線程在完成後與GUI線程同步。

你應該能夠實現你使用一些代碼列表這

private class DownloadFilesTask extends AsyncTask<String, List<Product>, Integer> { 
    protected List<Products> doInBackground(String... requestStrings) { 
     int count = requestStrings.length; 
     int results = 0; 
     for (int i = 0; i < count; i++) { 
      String requestString = requestStrings[i]; 
      HttpGet httpGet = new HttpGet(requestString); 
      httpGet.addHeader("Accept", "text/xml"); 
      String encodingString = "testuser:testpass"; 
      String sEncodedString = Base64Coder.encodeString(encodingString); 
      try{ 
      String sContent = fetchURL(requestString, sEncodedString); 
      XMLParser xmlParser = new XMLParser(); 
      List <Product> products = xmlParser.getProducts(sContent); 
      results++; 
      publishProgress(products); 
      } 
      catch(Exception ex){ 
      Log.e(TAG, ex.getMessage()); 
      } 
     } 
     return results; 
    } 

    protected void onProgressUpdate(Integer... progress) { 
     // TODO You are on the GUI thread, and the first element in 
     // the progress parameter contains the last progress 
     // published from doInBackground, so update your GUI 
    } 

    protected void onPostExecute(int result) { 
     // Processing is complete, result contains the number of 
     // results you processed 
    } 
} 

想什麼,執行通過調用

new DownloadFilesTask().execute(url1, url2, url3); 
+0

Asynctask或處理程序+線程,這取決於你Niko – tbruyelle

+2

AsyncTask是要走的路。 –

+0

這是很好的解決方案 – kablu

0

按照handler javadoc,我不認爲post()方法創建任何線程。如果我是對的,則在處理程序所連接的線程上執行Runnable。所以在這種情況下,這是活動線程,所以UI線程!這就是爲什麼你表現不佳。

您必須執行Thread執行Runnable。但是,這樣做,你將無法通過調用來更新你的活動就像您目前:

responseHandler.onProductsResponse(products); 

這是因爲你沒有任何更多的UI線程,只有UI線程被授權與UI交互(如此活動)。 所以你必須通過訪問你的Handler來取代這個電話。

Message msg = handler.obtainMessage(); 
Bundle bundle = new Bundle(); 
bundle.putSerializable("products", products); //not sure it will pass here 
msg.setData(bundle); 
handler.sendMessage(msg); 

和實施你的HandlerhandleMessage()方法:

@Override 
public void handleMessage(Message msg) 
{ 
    List <Product> products = msg.getData().getSerializable("products"); 
    responseHandler.onProductsResponse(products); 
} 

最後但並非最不重要的:在Handler有依然在活動線程創建。