36

I want to use OkHttp library for networking in Android. I started with the simple post example as written in their website:

public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(JSON, json);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  Response response = client.newCall(request).execute();
  return response.body().string();
}

With this call:

String response = post("http://www.roundsapp.com/post", json);

This call ends with NetworkOnMainThreadException.
I could wrap the call with an AsyncTask, but as far as I understand from the examples, the OkHttp library should have already taken care of that.. Am I doing something wrong?

Aviv Ben Shabat
  • 1,073
  • 2
  • 13
  • 33
  • 6
    It has nothing to do with that.. Read the question again. Bolded parts especially. Do you think about reading first? – Aviv Ben Shabat Jan 25 '15 at 10:37
  • I did read the question, and it has everything to do with that. You are dong network IO on the main thread. It doesn't matter what you **think** the library is doing, there is only one cause of this exception. – Simon Jan 25 '15 at 17:02
  • 3
    I didn't ask what is the **cause of the exception. I asked what is the right way to fix it.** The answer you added is one answer (That I was well aware of) but it wasn't the right way! The right way was written by @se_bastiaan. – Aviv Ben Shabat Jan 26 '15 at 07:47
  • 1
    I ended up here while searching for examples of asynchronous calls since the OkHttp page didn't have many. The Github page, which @se_bastiaan linked to, has several useful ones: https://github.com/square/okhttp/wiki/Recipes – Krøllebølle Jul 18 '15 at 11:04

3 Answers3

64

You should use OkHttp's async method.

public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

Call post(String url, String json, Callback callback) {
  RequestBody body = RequestBody.create(JSON, json);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  Call call = client.newCall(request);
  call.enqueue(callback);
  return call;
}

And then your response would be handled in the callback (OkHttp 2.x):

post("http://www.roundsapp.com/post", json, new Callback() {
  @Override
  public void onFailure(Request request, Throwable throwable) {
     // Something went wrong
  }

  @Override public void onResponse(Response response) throws IOException {
    if (response.isSuccessful()) {
       String responseStr = response.body().string();
       // Do what you want to do with the response.
    } else {
       // Request not successful
    }
  }
});

Or OkHttp 3.x/4.x:

post("http://www.roundsapp.com/post", "", new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            // Something went wrong
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()) {
                String responseStr = response.body().string();
                // Do what you want to do with the response.
            } else {
                // Request not successful
            }
        }
    });

Take a look at their recipes for more examples: http://square.github.io/okhttp/recipes/

se_bastiaan
  • 1,716
  • 14
  • 19
  • 2
    You should remove `Response response` because `.enqueue(callback)` returns nothing + there should be `void post(` instead of `String post(` – Hitesh Chavda Apr 03 '15 at 11:40
6

According to the OkHttp docs: It supports both synchronous blocking calls and async calls with callbacks. Your example is on main thread and Android since version 3.0 throws that exception if you try to do network calls on main thread

Better option is to use it together with retrofit and Gson: http://square.github.io/retrofit/ https://code.google.com/p/google-gson/

Here are the examples: http://engineering.meetme.com/2014/03/best-practices-for-consuming-apis-on-android/ http://heriman.net/?p=5

kjurkovic
  • 4,044
  • 2
  • 23
  • 28
  • Does anyone know if it's possible to do a "PATCH" using OkHttp? I have looked and I can't find any examples. Any ideas and suggestions are highly appreciated. – ito Jan 26 '15 at 20:26
  • It should be same as using post(). Definition is in Request class: public Builder patch(RequestBody body) { return method("PATCH", body); } – kjurkovic Jan 27 '15 at 08:22
  • how to handle the different response in retrofit ? – Ram Mandal Jan 05 '17 at 06:33
  • you can write custom deserializer http://www.javacreed.com/gson-deserialiser-example/ – kjurkovic Jan 05 '17 at 08:52
0

If you follows these steps to implement OKHTTP, then definitely you'll call multiple API on multiple screen by applying only two lines of code

UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
updateListener.getJsonData();

Step 1:

baseHTTPRequest = new BaseHTTPRequest();
    //    baseHTTPRequest.setURL("https://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demohttps://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo");
baseHTTPRequest.setURL("http://jsonparsing.parseapp.com/jsonData/moviesDemoItem.txt");
        baseHTTPRequest.setRequestCode(reqType);
        baseHTTPRequest.setCachedRequired(true);

        UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
        updateListener.executeRequest();

Step 2 : Create a request class

/** * Created by Deepak Sharma on 4/7/16. * This is a HTTP request class which has the basic parameters. * If you wants to add some more parameters, please make a subclass of that class * and add with your subclass. Don't modify this class. */

 public class BaseHTTPRequest<T> {

    private Context context;
    private String URL;
    private int requestCode;
    private List<T> listParameters;
    private String header;
    private boolean isCachedRequired;

    public Context getContext() {
        return context;
    }
    public void setContext(Context context) {
        this.context = context;
    }
    public void setURL(String URL) {
        this.URL = URL;
    }
    public String getURL() {
        return URL;
    }

    public int getRequestCode() {
        return requestCode;
    }

    public void setRequestCode(int requestCode) {
        this.requestCode = requestCode;
    }

    public List<T> getListParameters() {
        return listParameters;
    }

    public void setListParameters(List<T> listParameters) {
        this.listParameters = listParameters;
    }

    public String getHeader() {
        return header;
    }

    public void setHeader(String header) {
        this.header = header;
    }

    public boolean isCachedRequired() {
        return isCachedRequired;
    }
    public void setCachedRequired(boolean cachedRequired) {
        isCachedRequired = cachedRequired;
    }
}

step 4 : Create a listener class

import android.util.Log; import com.google.gson.Gson; import java.io.IOException; import dxswifi_direct.com.wifidirectcommunication.base.model.request.BaseHTTPRequest; import okhttp3.Call; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Callback; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response;

/** * Created by Deepak Sharma on 4/7/16. * @email : dpsharma.sharma1@gmail.com * This is a Simple java class which will help you for HTTP request/response and it will * throw the response to your correspondance activity. */

public class UpdateListener {

    private OnUpdateViewListener onUpdateViewListener;

    OkHttpClient okHttpClient = new OkHttpClient();
    BaseHTTPRequest mRequestModel;
    private String mURL = null;
    private Request mRequest = null;

    public interface OnUpdateViewListener {
        void updateView(String responseString, boolean isSuccess,int reqType);
    }

    public UpdateListener(OnUpdateViewListener onUpdateView, final BaseHTTPRequest requestModel) {
        this.mRequestModel = requestModel;
        this.onUpdateViewListener = onUpdateView;

        if (requestModel.isCachedRequired())
        {
            /*File httpCacheDirectory = new File(requestModel.getContext().getCacheDir(), "responses");
            Cache cache = null;
            cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
            if (cache != null) {
                okHttpClient.setCache(cache);
            }*/
        }

        /*mURL = null;
        if (requestModel.getListParameters()!=null && requestModel.getListParameters().size()>0)
        {
            HttpUrl.Builder urlBuilder = HttpUrl.parse(requestModel.getURL()).newBuilder();
            List<RequestParameter> requestParameters = requestModel.getListParameters();
            for (int i=0; i<requestParameters.size();i++)
            {
                urlBuilder.addQueryParameter(requestParameters.get(i).getKey(),requestParameters.get(i).getValue());
            }
            mURL = urlBuilder.build().toString();
        }
        else
        {
            mURL = requestModel.getURL();
        }*/

            mURL = requestModel.getURL();
        if (mRequestModel.getListParameters()!=null && mRequestModel.getListParameters().size()>1)
        {
            MediaType JSON = MediaType.parse("application/json; charset=utf-8");
            mRequest = new Request.Builder()
                    .url(mURL)
                    .post(RequestBody.create(JSON, new Gson().toJson(BaseHTTPRequest.class)))
                    .build();
        }
        else
        {
            mRequest = new Request.Builder()
                    .url(mURL)
                    .build();
        }

    }

    public void executeRequest()
    {
        Call call = okHttpClient.newCall(mRequest);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                onUpdateViewListener.updateView(NetworkException.getErrorMessage(e), false, mRequestModel.getRequestCode());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    // You can also throw your own custom exception
                    throw new IOException("Unexpected code " + response);
                } else {
                    Log.i("Response:",response.toString());
                    Log.i("Response body:",response.body().toString());
                    Log.i("Response message:",response.message());
                    onUpdateViewListener.updateView(response.body().string(),true, mRequestModel.getRequestCode());
                }
                // do something wih the result
            }
        });
    }
}

step 5 : From the activity you requesting, implement listener

public class HitAPIActivity extends AppCompatActivity implements View.OnClickListener, UpdateListener.OnUpdateViewListener{

@Override
    public void updateView(final String responseString, boolean isSuccess, int reqType) {

if (isSuccess)
        {

if (!responseString.contains("failure")
                    && !responseString.contains("Error")) {
                // Handle request on the basis of Request Type.
                switch (reqType) {
                    case ApiConstants.GET_CONTACTS:

break;

default:
break;

}

}
}

}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Maddy Sharma
  • 4,870
  • 2
  • 34
  • 40