如何在自己的线程中执行Web请求?

时间:2010-01-07 17:17:11

标签: java android multithreading

我正在创建一个Android应用程序,它必须在后台执行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);
}

从实现ServerResponseHandler的主活动调用方法sendRequest()。我猜这个请求是在自己的线程中执行的,并且通过调用

来执行

responseHandler.onProductsResponse(产品);

将产品列表(来自Web的数据)传递给主要活动。无论如何,由于性能不佳,如果有人能够纠正上述逻辑中的任何可能问题或建议任何其他(更好)选项,我将不胜感激。

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分:0)

根据handler javadoc,我认为post()方法不会创建任何线程。如果我是对的,它会在处理程序所附加的线程上执行Runnable。所以在这种情况下这是活动线程所以UI线程!这就是你表现不佳的原因。

您必须实施执行Thread的{​​{1}}。但通过这样做,您将无法像以前那样通过调用来更新您的活动:

Runnable

这是因为你不再是UI线程,只有UI线程被授权与UI交互(所以活动)。 因此,您必须访问responseHandler.onProductsResponse(products);

来替换此来电
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 ); 实施handleMessage()方法:

Handler

最后但并非最不重要的是:必须仍然在活动主题中创建@Override public void handleMessage( Message msg ) { List <Product> products = msg.getData().getSerializable( "products" ); responseHandler.onProductsResponse(products); }