androidasynchronousokhttpapprequests

Separate Class for OkHttp Requests


I use OkHttp for requests to my raspberry. I am thinking about putting the requests in a separate class.

Currently I have one method to send requests. The code is as follows:

private void sendRequest(String url, JSONObject json) {
        Log.d(TAG, "sendRequest: Das Json: " + json);
        // Authentication for the request to raspberry
        OkHttpClient.Builder client = new OkHttpClient.Builder();
        client.authenticator(new Authenticator() {
            @Override
            public Request authenticate(Route route, Response response) throws IOException {
                String credential = Credentials.basic("username", "password");
                return response.request().newBuilder()
                        .header("Authorization", credential)
                        .build();
            }
        });

        // Sending out the request to the raspberry
        OkHttpClient okHttpClient = client.build();

        RequestBody body = RequestBody.create(null, new byte[]{});
        if( json != null) {
            body = RequestBody.create(MediaType.parse(
                    "application/json"),
                    json.toString()
            );
        }

        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();

        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d(LOG, "Big Fail");

                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    ResponseBody responseBody = response.body();
                    if( !response.isSuccessful() ) {
                        Log.d(TAG, "onResponse: We are in !response.successful()");
                        throw new IOException("Response not successful: " + response );
                    }
                    Log.d(LOG, "onResponse: Response is: " + responseBody.string());
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.d(LOG, "onResponse: failed!" + e);
                }
            }
        });
    }

Here is an example how the sendRequest() function is called:

private void makePremixCall(Premix premix) {
        JSONArray jsonArray = new JSONArray();
        ArrayList<Premixable> usedPremixables = premix.getUsedPremixables();
        for(Premixable usedPremixable: usedPremixables) {
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("Silo", usedPremixable.getmSilo());
                jsonObject.put("Gramm", usedPremixable.getmKgPerCow() * mFeeding.getmNumberOfCows());
                jsonArray.put(jsonObject);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("Components", jsonArray);
            sendRequest("http://192.168.178.49:5000/evaluatePost", jsonObject);
        } catch (JSONException e) {
            e.printStackTrace();
            Log.d(TAG, "makePremixCall: " + e);
        }
    }

My problem with this: I would like to have a separate class, which offers the function makePremix(Premix premix) and other functions that I need.

The only solution that comes to my mind is implementing the requests synchronously in the separate class and call that separate class in an AsyncTask in the class I am working in.

Do I oversee something? Is there a way to create a separate class and still use the OkHttp enqueue method?


Solution

  • You could extract makePremix(Premix premix) in a separate class and make sendRequest() public (or maybe package-private depending on your use case).

    public void sendRequest(String url, JSONObject json)
    

    However since sendRequest is generic and can be used by any other makeAnotherCall() in some other class you would need to get back result of every requests. Hence you can extract the Callback out of sendRequest()

    public void sendRequest(String url, JSONObject json, Callback callback)
    

    Now your sendRequest will look like

    private void sendRequest(String url, JSONObject json) {
            Log.d(TAG, "sendRequest: Das Json: " + json);
            // Authentication for the request to raspberry
            OkHttpClient.Builder client = new OkHttpClient.Builder();
            client.authenticator(new Authenticator() {
                @Override
                public Request authenticate(Route route, Response response) throws IOException {
                    String credential = Credentials.basic("username", "password");
                    return response.request().newBuilder()
                            .header("Authorization", credential)
                            .build();
                }
            });
    
            // Sending out the request to the raspberry
            OkHttpClient okHttpClient = client.build();
    
            RequestBody body = RequestBody.create(null, new byte[]{});
            if( json != null) {
                body = RequestBody.create(MediaType.parse(
                        "application/json"),
                        json.toString()
                );
            }
    
            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();
    
            okHttpClient.newCall(request).enqueue(callback);
        }
    

    Hope it makes sense!

    Also as a side note, see that you are creating a new OkHttp Client every time you call sendRequest. You could probably optimise memory here by caching the client and reusing it.