Android, Volley Request, the response is blocking main thread
Asked Answered
A

2

11

Something bad is happening when using Volley to treat a large response:

String url = AppHelper.DOMAIN + "/service/pages/profile_update.json";

this.infoTextView.setText(getString(R.string.profile_info_updating));

final StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONObject json = new JSONObject(response);

                    if (json.getBoolean("success")) {
                        // manage JSON object here
                    } else {
                        Toast.makeText(ProfileActivity.this,
                                getString(R.string.connection_problem_server),
                                Toast.LENGTH_LONG).show();
                    }
                } catch (JSONException e) {
                    ProfileActivity.this.infoTextView.setText(
                            getString(R.string.profile_info_updating_error));

                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        ProfileActivity.this.infoTextView.setText(
                getString(R.string.profile_info_updating_error));

        if (error.networkResponse != null && error.networkResponse.statusCode == 401) {
            Toast.makeText(ProfileActivity.this,
                    getString(R.string.connection_problem_permission),
                    Toast.LENGTH_LONG).show();
        }

        new android.os.Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if (ProfileActivity.this.swipeRefreshLayout != null) {
                    ProfileActivity.this.swipeRefreshLayout.setRefreshing(false);
                }
            }
        }, 1000);

        error.printStackTrace();
    }
}) {
    @Override
    protected Map<String, String> getParams() {
        Map<String, String> params = new HashMap<>();
        params.put("auth_token", ProfileActivity.this.defaultUser.getAuthenticationToken());
        return params;
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> params = new HashMap<>();
        params.putAll(super.getHeaders());
        params.put("Accept-Encoding", "gzip,deflate");
        return params;
    }

    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        StringBuilder output = new StringBuilder();
        try {
            GZIPInputStream gStream = new GZIPInputStream(new ByteArrayInputStream(response.data));
            InputStreamReader reader = new InputStreamReader(gStream);
            BufferedReader in = new BufferedReader(reader, 16384);

            String read;

            while ((read = in.readLine()) != null) {
                output.append(read).append("\n");
            }
            reader.close();
            in.close();
            gStream.close();
        } catch (IOException error) {
            error.printStackTrace();
            return Response.error(new ParseError());
        }

        return Response.success(output.toString(), HttpHeaderParser.parseCacheHeaders(response));
    }
};

stringRequest.setRetryPolicy(new RetryPolicy() {
    @Override
    public int getCurrentTimeout() {
        // 40 seconds
        return 40000;
    }

    @Override
    public int getCurrentRetryCount() {
        return DefaultRetryPolicy.DEFAULT_MAX_RETRIES;
    }

    @Override
    public void retry(VolleyError error) throws VolleyError {
        throw error;
    }
});

Volley.newRequestQueue(this).add(stringRequest);

this code block the main thread, freezing the application.

Additionally, I set some header values to allow gzip response and a code to handle the data. But it is not the piece that make the undesired behavior. The application freeze only when onResponse(String response) starts.

What can I do to avoid this?

Assai answered 25/7, 2016 at 12:20 Comment(2)
It probably has to do with the fact that you're doing the JSON parsing on the UI thread, instead of in parseNetworkResponseSkittish
Code seems to be fine.. could you expose other part of code around this network request?Shy
V
21

onResponse and onErrorResponse is called on UI thread hence any heavy operation done inside these methods will make you application less responsive. I guess you are trying to parse the response in onResponse() which is incorrect.

You have to move to parsing logic to parseNetworkResponse since this is the method which is called in background thread. Refer the below link for more details :

https://developer.android.com/training/volley/request-custom.html

Valetudinary answered 25/7, 2016 at 12:32 Comment(2)
what if the call request was made from IntentService, will onResponse() execute on UI thread then?Blast
Doest not matter what is the calling thread. onResponse() will be called on UI thread.Valetudinary
A
0

If it help someone , try to create a new thread in a method inside onResponse , inside that thread execute your parsing data. I hope the answer works for you

Adscititious answered 9/7, 2020 at 17:10 Comment(1)
Hi, as explained in the accepted answer 4 years ago, response processing should be done in parseNetworkResponse which already runs on a worker thread.Ambivert

© 2022 - 2024 — McMap. All rights reserved.