4

Possible Duplicate:
NetworkOnMainThreadException

For a long time, I've been using generic code that does http requests in an AsyncTask. The AsyncTask returns an HttpResponse object. Everything worked great and the GUI thread never froze or anything.

Now, suddenly, this creates a NetworkOnMainThreadException:

serverResponse.getEntity().getContent();

What the heck?? Why is getEntity() considered networking?? In my mind, that line merely converts a response to an inputstream and should not need a network connection. Who made this decision? WHY did they decide this should be networking?

The async task:

public class AsyncHttpTask extends AsyncTask<HttpRequestInfo, Integer, HttpRequestInfo> {

public AsyncHttpTask() {
    super();
}

protected HttpRequestInfo doInBackground(HttpRequestInfo... params) {
    HttpRequestInfo rinfo = params[0];
    try{
        HttpClient client = new DefaultHttpClient();
        HttpResponse resp = client.execute(rinfo.getRequest());
        rinfo.setResponse(resp);
    }
    catch (Exception e) {
        rinfo.setException(e);
    }
    return rinfo;
}

@Override
protected void onPostExecute(HttpRequestInfo rinfo) {
    super.onPostExecute(rinfo);
    rinfo.requestFinished();
}   

Callback interface:

    public interface HttpCallback {

        public void onResponse(HttpResponse serverResponse);
        public void onError(Exception e);

    }

HttpRequestInfo:

public class HttpRequestInfo {

    private HttpUriRequest request_;
    private HttpCallback callback_;
    private Exception exception_;
    private HttpResponse response_;

    public HttpRequestInfo(HttpUriRequest request, HttpCallback callback) {
        super();
        request_ = request;
        callback_ = callback;
    }

    public HttpUriRequest getRequest() {
        return request_;
    }

    public void setRequest(HttpUriRequest request) {
        request_ = request;
    }

    public HttpCallback getCallback() {
        return callback_;
    }

    public void setCallback(HttpCallback callback) {
        callback_ = callback;
    }

    public Exception getException() {
        return exception_;
    }

    public void setException(Exception exception) {
        exception_ = exception;
    }

    public HttpResponse getResponse() {
        return response_;
    }

    public void setResponse(HttpResponse response) {
        response_ = response;
    }

    public void requestFinished(){
        if(exception_ != null){
            callback_.onError(exception_);
        }
        else {
            callback_.onResponse(response_);
        }
    }
}

Then I use jackson to convert the json response to an object. That's this is where the exception occurs:

@Override
public <T> T handleResponse(HttpResponse serverResponse, Class<T> typeOfResponse) {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    T responseObject = null;
    try {
        responseObject = mapper.readValue(serverResponse.getEntity().getContent(),typeOfResponse); //THIS LINE IS EVIL
    } catch (JsonParseException e) {
        throw new ARException("Couldn't handle the response because the http response contained malformed json.",e);
    } catch (JsonMappingException e) {
        throw new ARException("Mapping the json response to the response object " + typeOfResponse + " failed.",e);
    } catch (IllegalStateException e) {
        throw new ARException("Couldn't convert the http response to an inputstream because of illegal state.",e);
    } catch (IOException e) {
        throw new ARException("Couldn't convert the http response to an inputstream.",e);
    }
    return responseObject;
}
Community
  • 1
  • 1
Adam
  • 959
  • 10
  • 23
  • I read that question and the blog post. The difference is, I AM doing my networking in an async task. I get an HttpResponse back. It's only when I call HttpResponse.getEntity() that the exception happens. – Adam Nov 20 '12 at 06:18

1 Answers1

2

Because you must work with network in separate thread and not main. You can use AsyncTask or Thread + Handler. If you are using AsyncTask all work with network you must perform in doInBackground part.

Artyom Kiriliyk
  • 2,513
  • 1
  • 17
  • 21
  • 1
    Is httpResponse.getEntity().getContent() considered networking? Why? – Adam Nov 20 '12 at 06:27
  • I posted all of my code. Aren't I doing all networking in an async task? – Adam Nov 20 '12 at 06:31
  • httpResponse.getEntity().getContent() works with network because you get data from HttpResponse. Where you execute handleResponse? – Artyom Kiriliyk Nov 20 '12 at 06:38
  • I call handleResponse in the main thread. But the object is called http RESPONSE. I thought HttpResponse was the response that gets back AFTER the networking. All httpResponse.getEntity().getContent() does is convert the response to an inputstream. That shouldn't be networking!! :) – Adam Nov 20 '12 at 06:41
  • If you use handleResponse in Activity try this: `Thread th = new Thread() { @Override public void run() { httpResponse.getEntity().getContent(); } }; th.start()` – Artyom Kiriliyk Nov 20 '12 at 06:48
  • 2
    It definitely works if I use a new thread or an async task. I guess my real question is, WHY is this considered networking? If I had known this was considered networking, I would never have done it like this! – Adam Nov 20 '12 at 07:03
  • It's wrong create thead in asynk task. If you want to use `httpResponse.getEntity().getContent();` in asynk task use it in doInBackground without thead. WHY is this considered networking? - Because even compiler said this is NetworkOnMainThreadException. HttpEntity is an entity that can be sent or received with an HTTP message. Entities can be found in some requests and in responses, where they are optional. Work with HTTP protocol need network. – Artyom Kiriliyk Nov 20 '12 at 07:13