views:

476

answers:

2

Hi,

I am creating an android application which has to execute web requests in the background and then handle the received data and modify the user interface according to the server response.

The goal of posting requests and handling data in the background is to avoid the freezing of user interface. Currently however I notice that the user interface is freezing so I am not sure the logic is working as it is supposed to.

Here is the part of code which is supposed to post requests and handle responses in its own thread and then pass the data to 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);
}

The method sendRequest() is called from the main activity which implements ServerResponseHandler. I guess the request is executed in its own thread and by calling

responseHandler.onProductsResponse(products);

the list of products (data from the web) is passed to main activity. Anyway due to poor performance I would appreciate if anyone could correct any possible issue in the logic above or suggest any other (better) option.

+7  A: 

I'd suggest you take a look at ASyncTask class (available since Android 1.5).

It simplifies the process of creating a background Thread that synchronizes with the GUI thread once it's complete.

You should be able to achieve what you're trying using code something list this

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
     }
 }

And execute by calling

new DownloadFilesTask().execute(url1, url2, url3);
Reto Meier
Asynctask or handler+thread, it's up to you Niko
kosokund
AsyncTask is the way to go.
mbaird
A: 

According to the handler javadoc, I don't think the post() method create any threads. If I'm right it execute the Runnable on the thread to which the handler is attached. So in this case this is the activity thread so the UI thread ! That's why you have poor performance.

You have to implement a Thread which execute your Runnable. But by doing that, you won't be able to update your activity like you currently do by calling :

responseHandler.onProductsResponse(products);

This is because you are not any more in the UI thread, and only the UI thread is authorized to interact with the UI (so the activity). So you have to replace this call by accessing your 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 );

And implementing the handleMessage() method for your Handler :

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

Last but not least : the Handler has to still be created in the activity thread.

kosokund