【问题标题】:How to execute web request in its own thread?如何在自己的线程中执行 Web 请求?
【发布时间】:2010-01-08 02:14:36
【问题描述】:

我正在创建一个 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);
}

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

responseHandler.onProductsResponse(products);

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

【问题讨论】:

    标签: java android multithreading


    【解决方案1】:

    我建议你看看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);
    

    【讨论】:

      【解决方案2】:

      根据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 );
      

      并为您的Handler 实现handleMessage() 方法:

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

      最后但同样重要的是:Handler 仍必须在活动线程中创建。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-28
        • 1970-01-01
        • 2021-08-18
        相关资源
        最近更新 更多