Josh Hansen
Josh Hansen

Reputation: 1478

Why does this Android Volley request never complete?

Consider this code in an Android activity, using the Volley HTTP library. The HTTP request never completes. It neither receives a normal response nor an error response. But if the while (!done) block is commented out, then everything completes normally. This surprises me since with Volley I'm making a RequestQueue which contains a thread pool where entirely separate threads are used to carry out the HTTP request. So why does the request never finish if this thread is sleeping?

The code:

package com.adobe.instore.activities;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

import com.adobe.instore.R;
import com.adobe.instore.Urls;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONObject;

public class VolleyTestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_volley_test);
    }

    private static boolean done = false;
    protected void makeRequest(View v) {
        Log.i(getLocalClassName(), "Request");

        RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
        queue.start();
        queue.add(new JsonObjectRequest(Request.Method.GET, Urls.STATIC_URL + "/profiles.json", null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                Log.i(getLocalClassName(), "Response");
                done = true;
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(getLocalClassName(), "Error");
            }
        }));

        Log.i(getLocalClassName(), "Awaiting completion");
        while(!done) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.i(getLocalClassName(), "Done");
    }
}

Upvotes: 0

Views: 1014

Answers (2)

Enzokie
Enzokie

Reputation: 7415

Views are rendered in the Main Thread (sometimes called UI Thread). The loop you made blocks the rendering and the other code that follows. Technically it is a bad idea to call Thread.sleep(...); in this thread since many things will be affected. Volley is a http library designed to make your life simpler by not needing to explicitly call a Thread of your own.

In Volley all the networking and cache dispatching are done in a Separate thread (behind the hood) while the response is sent back to the Main thread. That just means that onResponse and onError happens in the Main thread.

To make it more simpler you can do like this:

public class VolleyTestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_volley_test);
    }

    public void makeRequest(View v) {
        Log.i(getLocalClassName(), "Request");

        RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
        queue.start();
        queue.add(new JsonObjectRequest(Request.Method.GET, Urls.STATIC_URL + "/profiles.json", null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                Log.i(getLocalClassName(), "Response");
                Log.i(getLocalClassName(), "Done");
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(getLocalClassName(), "Error");
            }
        }));

        Log.i(getLocalClassName(), "Awaiting completion");
    }
}

Furthermore the while() and Thread.sleep keeps the Thread busy. So any executions queued in the Main thread are unreachable till the loop is done (but it wont happen). You might be thinking that the onResponse can bypass that infinite loop? The answer is NO; because onResponse is queued by the Main thread and not the background Thread. To illustrate see figure below: enter image description here

Figure 1 : Android Volley internal architecture (image is from the docs)

If you look that box that says Parsed response delivered on main thread which is colored as BLUE meaning it is the Main thread who call it (to simplify it means onResponse and onError are called by the Main thread) unless it is orange or green then loop will be bypassed by your boolean.

Upvotes: 1

Randyka Yudhistira
Randyka Yudhistira

Reputation: 3652

Volley onResponse and onErrorResponse is called on UI thread. So if your main thread is sleeping, then onResponse and onErrorResponse will not be called

Upvotes: 1

Related Questions