4

I am using OKHttp to perform Post request to server, as follow:

public class NetworkManager {
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    OkHttpClient client = new OkHttpClient();

    String post(String url, JSONObject json) throws IOException {
        try {
            JSONArray array = json.getJSONArray("d");
            RequestBody body = new FormEncodingBuilder()
                    .add("m", json.getString("m"))
                    .add("d", array.toString())
                    .build();
            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();
            Response response = client.newCall(request).execute();
            return response.body().string();
        } catch (JSONException jsone) {
            return "ERROR: " + jsone.getMessage();
        }
    }
}

and call it with:

NetworkManager manager = new NetworkManager();
String response = manager.post("http://www.example.com/api/", jsonObject);

When I try to run the App, it prompts an error in the logcat:

android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1273)

With reference to other questions in SO, I added this to override the policy:

if (android.os.Build.VERSION.SDK_INT > 9)
{
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
}

Yet I think this is unhealthy and I would like to put the NetworkManager actions to background. How can I do so?

Raptor
  • 53,206
  • 45
  • 230
  • 366

1 Answers1

12

Since OkHttp supports async way too, so IMO you can refer to the following GET request sample, then apply for your POST request:

        OkHttpClient client = new OkHttpClient();
        // GET request
        Request request = new Request.Builder()
                .url("http://google.com")
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                Log.e(LOG_TAG, e.toString());
            }
            @Override
            public void onResponse(Response response) throws IOException {
                Log.w(LOG_TAG, response.body().string());
                Log.i(LOG_TAG, response.toString());
            }
        });

Hope it helps!

BNK
  • 23,994
  • 8
  • 77
  • 87
  • 1
    Would recommend the OkHttp asynchronous option. – novak Dec 08 '15 at 03:06
  • Looks promising. How do I notify the main class when the response is ready? My current logic is synchronous and directly return the response string, then the main class parses the response to do further actions. – Raptor Dec 08 '15 at 03:14
  • 2
    As you see, inside `onResponse` you will do that, if you want to update UI or display Toast, you will also need `mHandler = new Handler(Looper.getMainLooper());`. If the request inside another class (for example Utils.java), I think you should use a listener interface – BNK Dec 08 '15 at 03:17
  • 2
    You can refer to my GitHub sample project, it's a POST request. https://github.com/ngocchung/MultipartOkHttp – BNK Dec 08 '15 at 03:25
  • Great example, but only 1 question remained. I somehow need to update a variable in the class (`MainActivity`) which called the `NetworkManager`. How do I call a function on `MainActivity` ? – Raptor Dec 08 '15 at 04:14
  • Sorry, I don't understand your idea. Can you give an example? – BNK Dec 08 '15 at 04:28
  • @BNK I asked another question for this issue: http://stackoverflow.com/questions/34193555/okhttp-trigger-callback-in-originated-class-after-finishing-network-actions . Can you take a look? Thanks. *Sorry I'm a newbie in Android* – Raptor Dec 10 '15 at 04:13
  • How to do the same in Kotlin? – zaitsman Nov 26 '21 at 01:35