Search code examples
androidandroid-asynctaskcountdownlatch

Android : AsyncTask not reaching onPostExecute


I am using AsyncTask to avoid networkonmainthreadexception on my Android Library Project, now what I want to do is to get the value to be returned to my variable and wait for it before executing the next line of code. I used CountDownLatch to do this.

The way I execute my request and call my AsyncTask is written below.. So I used CountDownLatch to wait for the response before returning the value that I want to return.

public MyObject getMyObject(){

    final String url = "http://[myip]:8080/retrieve";

    try{
        Response response = executeRequest(url);
        final MyObject myObject = om.readValue(response.body().string(),
                new TypeReference<MyObject>() {
                });
        return myObject;
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;

}



private Response executeRequest(String url){

    try {
      //Simplified please just ignore this..
      GenericAsyncParams genericAsyncParams = createParams(......);

      final CountDownLatch countDownLatch = new CountDownLatch(1);
      ResponseListener responseListener = new ResponseListener(countDownLatch);
      MyAsyncTask myAsyncTask = new AsyncTask(responseListener);
      myAsyncTask.execute(genericAsyncParams);
      countDownLatch.await();

      //get the response from the listener class.
      Response response = responseListener.getResponse();
      return response;
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    return null;
  }

I am also aware that asyncTask.execute(args).get() could cause the exception, so I used a listener to update the value from the caller, I call setResponse on onPostExecute of my AsyncTask.

public class ResponseListener {

    private static final String TAG = ResponseListener.class.getName();

    private Response response;
    private CountDownLatch countDownLatch;

    public ResponseListener(CountDownLatch countDownLatch) {
        this.response = null;
        this.countDownLatch = countDownLatch;
    }

    public void setResponse(Response response){
        this.response = response;   
        Log.e(TAG, "Executing countdown..");
        countDownLatch.countDown();
    }

    public Response getResponse() {
        return response;
    }

    public CountDownLatch getCountDownLatch() {
        return countDownLatch;
    }
}

Now this is my AsyncTask Note: requestProcessor is a wrapper class for okHttp.

public class MyAsynctask extends AsyncTask<GenericAsyncParams, Void, Response>{


    private static final String TAG = MyAsyncTask.class.getName();

    private ResponseListener listener;

    public MyAsynctask(ResponseListener listener) {
        this.listener = listener;
    }

    @Override
    protected Response doInBackground(GenericAsyncParams... genericAsyncParamses) {
        Response response = null;
        GenericAsyncParams genericAsyncParams = genericAsyncParamses[0];
        String url = genericAsyncParams.getUrl();
        String method = genericAsyncParams.getMethod();
        RequestProcessor requestProcessor = genericAsyncParams.getRequestProcessor();

        try {
            Request.Builder builder;
            if(method.equalsIgnoreCase("POST")){
                builder = new Request.Builder()
                        .post(genericAsyncParams.getRequestBody())
                        .url(url)
                        .headers(headers);
            } else  {
                builder = new Request.Builder()
                        .headers(headers)
                        .get()
                        .url(url);
            }
            final Request request = builder.build();
            response = requestProcessor.client().newCall(request).execute();
            Log.d(TAG, "returning okHttp response..");
            return response;
        } catch (Exception e){
            Log.e(TAG, String.format("ERROR.. %s", ExceptionUtils.getMessage(e)));
        }

        return response;
    }


    @Override
    protected void onPostExecute(Response response) {
        if(listener != null){
            Log.d(TAG, "Updating response : onPostExecute..");
            listener.setResponse(response);
        } else {
            super.onPostExecute(response);
        }
    }

}

The last line of my log is

07-10 23: 47:07.008 28409-28530/com.aaron.android.android.lib D/com.aaron.android.android.lib.api.tasks.MyAsyncTask: returning okHttp response..

Solution

  • NetworkOnMainException reminds us to not block the main UI thread. However, you are still blocking it by using a CountDownLatch to wait for the response. Since onPostExecute() runs on the main thread, you have blocked it from executing. You cannot block the main thread while waiting for the network connection to finish. Instead, allow executeRequest() to return so that the UI can respond appropriately.