Stephen
Stephen

Reputation: 10079

Show response everytime when hitting the api in volley

I need to get the response 8 times nearly(dynamic) based on the array list size.So I had used for loop.inside the for loop, I am using volley get response.

While hitting the api everytime,I need to get the onResponse.

Below I have posted the logcat and relevant code:

Logcat: (Edited)

 E/getAvaArrStr: 
 E/urlAva: 

 E/getAvaArrStr: 
 E/urlAva: 

 E/getAvaArrStr: 
 E/urlAva: 

 E/getAvaArrStr: 
 E/urlAva: 

 E/getAvaArrStr: 
 E/urlAva:

 /* Response */

 E/ResponseAvatar: 
 E/url: 
 E/CheckArrBit: 

 E/ResponseAvatar: 
 E/url: 
 E/CheckArrBit: 

 E/ResponseAvatar: 
 E/url: 
 E/CheckArrBit: 

 E/ResponseAvatar: 
 E/url: 
 E/CheckArrBit: 

CardsFragment.java: (Edited)

RequestQueue queue = Volley.newRequestQueue(getActivity());

for (int i = 0; i < alAvaArr.size(); i++) {

    getAvaArrStr = alAvaArr.get(i);

    Log.e("getAvaArrStr", "" + getAvaArrStr);

    urlAva = BurblrUtils.BR_AVATAR_IMAGE + getAvaArrStr + "&android=1";

    Log.e("urlAva", urlAva);


    requestAva = new StringRequest(Request.Method.GET, urlAva, new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {
            if (response != null && !response.startsWith("<HTML>")) {
                Log.e("ResponseAvatar", response);

                dialog.dismiss();

                try {

                    Toast.makeText(getActivity(), "Running ", Toast.LENGTH_SHORT).show();

                    String url = response.replace("\\", "");
                    url = url.replace("\"", "");

                    Log.e("url", url);

                    arrBitMap.add(url);

                    Log.e("CheckArrBit", "" + arrBitMap);

                    //     Glide.with(getActivity()).load(url).placeholder(R.drawable.ic_launcher).error(R.drawable.ic_launcher).into(img);


                    getSwipeImage();

                    myAppAdapter.notifyDataSetChanged();

                } catch (Exception e) {
                    e.printStackTrace();
                    dialog.dismiss();
                }

            } else {
                dialog.dismiss();
            }
        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            if (error != null) {
                Log.e("error", error.toString());
                dialog.dismiss();
            }

        }
    }) {
        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<String, String>();

            params.put("file", getAvaArrStr);

            Log.e("paramsImg", "" + params);

            Log.e("RunningParams", "Testing");


            return params;
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            params.put("Content-Type", "application/x-www-form-urlencoded");
            return params;
        }
    };

       queue.add(requestAva);

        queue.getCache().remove(urlAva);

}

Expected Log Response Sequence:

E/getAvaArrStr: -> E/urlAva: -> E/ResponseAvatar: -> E/url: -> E/CheckArrBit:

I need to get the response everytime on running the loop.That means nearly 8 times, based on the arrayList size, I have to get the response message,is it possible in volley? any suggestion to overcome this issue.

Upvotes: 6

Views: 2231

Answers (6)

user5703518
user5703518

Reputation:

You must create a function. The function makeRequest handles your next Api call

public class MainActivity extends AppCompatActivity {

    RequestQueue queue;
    int mIndex = 0 ;
    ArrayList<String> alAvaArr;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mQueue = Volley.newRequestQueue(getActivity());
        alAvaArr = ///////// initialize here

        mIndex  = 0;
        makeRequest(alAvaArr.get(mIndex));
    }

    public void makeRequest( String arg){



        getAvaArrStr = arg;

        Log.e("getAvaArrStr", "" + getAvaArrStr);

        urlAva = BurblrUtils.BR_AVATAR_IMAGE + getAvaArrStr + "&android=1";

        Log.e("urlAva", urlAva);


        requestAva = new StringRequest(Request.Method.GET, urlAva, new Response.Listener<String>() {

            @Override
            public void onResponse(String response) {
                if (response != null && !response.startsWith("<HTML>")) {
                    Log.e("ResponseAvatar", response);

                    dialog.dismiss();

                    try {

                        Toast.makeText(getActivity(), "Running ", Toast.LENGTH_SHORT).show();

                        String url = response.replace("\\", "");
                        url = url.replace("\"", "");

                        Log.e("url", url);

                        arrBitMap.add(url);

                        Log.e("CheckArrBit", "" + arrBitMap);

                        //     Glide.with(getActivity()).load(url).placeholder(R.drawable.ic_launcher).error(R.drawable.ic_launcher).into(img);


                        getSwipeImage();

                        myAppAdapter.notifyDataSetChanged();

                        mIndex++;
                        if(mIndex < alAvaArr.size()){
                            makeRequest(alAvaArr.get(mIndex));
                        } 

                    } catch (Exception e) {
                        e.printStackTrace();
                        dialog.dismiss();
                    }

                } else {
                    dialog.dismiss();
                }
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                if (error != null) {
                    Log.e("error", error.toString());
                    dialog.dismiss();
                }

            }
        }) {
            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<String, String>();

                params.put("file", getAvaArrStr);

                Log.e("paramsImg", "" + params);

                Log.e("RunningParams", "Testing");


                return params;
            }

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> params = new HashMap<String, String>();
                params.put("Content-Type", "application/x-www-form-urlencoded");
                return params;
            }
        };

        mQueue.add(requestAva);

 }

Upvotes: 1

kalin
kalin

Reputation: 3576

I will add another option triggered by the words of BNK

Because Volley is asynchronous...

Here we have 2 kind of solutions essentially doing synchronization of your requests.

1) solution to sync requests by triggering them from within the response callback of the previous one (request chaining)

2) my solution using Futures to sync the calls thus converting them in blocking calls (one wait for the previous one to finish).

they both work and will execute almost with the same speed.

however they all work against the multithreading advantage of Volley.

If your only goal is to link the URLs you provide first with the responses then you can simply have MAP and put them in the right place when response is received.

in this example i will use Map (urlAndResponses) to combine your 2 Collections

alAvaArr and arrBitMap

so basically instead of this :

for (int i = 0; i < alAvaArr.size(); i++) {

    getAvaArrStr = alAvaArr.get(i);

you put:

 final Map<String, String> urlAndResponses = Collections.synchronizedMap(new HashMap<String, String>());
            for (Map.Entry<String, String> entry:urlAndResponses.entrySet()) {
               final String getAvaArrStr = entry.getKey();

then in your callback instead of :

arrBitMap.add(url);

you put:

urlAndResponses.put(getAvaArrStr, url);

This way you will not have the logs as you want but you will have the response in the right place at any moment and still all the requests will run asynchronously.

Upvotes: 1

kalin
kalin

Reputation: 3576

From your requirements i suppose you need synchronous execution. So ill advise to use futures. It is also important to note that in order not to block the main thread you have execute the whole loop on a separate thread. ex:

new Thread(new Runnable() {
                @Override
                public void run() {
..your loop...
 }
            }).start();

when you create your request:

requestAva = new StringRequest(Request.Method.GET, urlAva, new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {
            if (response != null && !response.startsWith("<HTML>")) {
                Log.e("ResponseAvatar", response);

                dialog.dismiss();

                try {

                    Toast.makeText(getActivity(), "Running ", Toast.LENGTH_SHORT).show();

                    String url = response.replace("\\", "");
                    url = url.replace("\"", "");

                    Log.e("url", url);

                    arrBitMap.add(url);

                    Log.e("CheckArrBit", "" + arrBitMap);

                    //     Glide.with(getActivity()).load(url).placeholder(R.drawable.ic_launcher).error(R.drawable.ic_launcher).into(img);


                    getSwipeImage();

                    myAppAdapter.notifyDataSetChanged();

                } catch (Exception e) {
                    e.printStackTrace();
                    dialog.dismiss();
                }

            } else {
                dialog.dismiss();
            }
        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            if (error != null) {
                Log.e("error", error.toString());
                dialog.dismiss();
            }

        }
    })

change to this:

RequestFuture<String> future = RequestFuture.newFuture() {
 @Override
    public synchronized void onResponse(String response) {
 if (response != null && !response.startsWith("<HTML>")) {
                Log.e("ResponseAvatar", response);

                dialog.dismiss();

                try {

                    Toast.makeText(getActivity(), "Running ", Toast.LENGTH_SHORT).show();

                    String url = response.replace("\\", "");
                    url = url.replace("\"", "");

                    Log.e("url", url);

                    arrBitMap.add(url);

                    Log.e("CheckArrBit", "" + arrBitMap);

                    //     Glide.with(getActivity()).load(url).placeholder(R.drawable.ic_launcher).error(R.drawable.ic_launcher).into(img);


                    getSwipeImage();

                    myAppAdapter.notifyDataSetChanged();

                } catch (Exception e) {
                    e.printStackTrace();
                    dialog.dismiss();
                }

            } else {
                dialog.dismiss();
            }
       super.onResponse(response);
    }
    @Override
    public synchronized void onErrorResponse(VolleyError error) {
       if (error != null) {
                Log.e("error", error.toString());
                dialog.dismiss();
            }
        super.onErrorResponse(error);
    }
};
 requestAva = new StringRequest(Request.Method.GET, urlAva, future, future) {...

note like this you put as listeners your Future and your previous listeners are not implemented in your Future. then when you add the request

 queue.add(requestAva);

change to :

queue.add(requestAva);

  try {
    future.get();
    // the response is handled by your Future synchroniously
  } catch (InterruptedException e) {
    // handle the error
  } catch (ExecutionException e) {
    // handle the error
  }

Upvotes: 0

BNK
BNK

Reputation: 24114

Because Volley is asynchronous, so IMO, you should not put the requests inside for-loop like the code in your question. Please refer to the following sample code then apply its logic to your app. Hope it helps!

public class MainActivity extends AppCompatActivity {
    private int num = 0;
    private JsonArrayRequest jsonArrayRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final RequestQueue requestQueue = Volley.newRequestQueue(this);
        String url = "http://...";
        jsonArrayRequest = new JsonArrayRequest(url, new Response.Listener<JSONArray>() {
            @Override
            public void onResponse(JSONArray response) {
                Log.i("Num", String.valueOf(num));
                Log.i("Response", response.toString());
                if (num < 8) {
                    num++;
                    requestQueue.add(jsonArrayRequest);
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("Error", error.toString());
            }
        });
        num++;
        requestQueue.add(jsonArrayRequest);
    }
}

Logcat output as below:

03-28 13:14:29.885 13262-13262/com.example.googlevolley I/Num: 1
03-28 13:14:29.885 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]
03-28 13:14:29.935 13262-13262/com.example.googlevolley I/Num: 2
03-28 13:14:29.955 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]
03-28 13:14:30.085 13262-13262/com.example.googlevolley I/Num: 3
03-28 13:14:30.085 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]
03-28 13:14:30.245 13262-13262/com.example.googlevolley I/Num: 4
03-28 13:14:30.245 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]
03-28 13:14:30.266 13262-13262/com.example.googlevolley I/Num: 5
03-28 13:14:30.266 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]
03-28 13:14:30.296 13262-13262/com.example.googlevolley I/Num: 6
03-28 13:14:30.296 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]
03-28 13:14:30.306 13262-13262/com.example.googlevolley I/Num: 7
03-28 13:14:30.306 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]
03-28 13:14:30.316 13262-13262/com.example.googlevolley I/Num: 8
03-28 13:14:30.316 13262-13262/com.example.googlevolley I/Response: [{"id":"1","name":"Information Technology"},{"id":"2","name":"Human Resources"},{"id":"3","name":"Marketing and PR"},{"id":"4","name":"Research and Developement"}]

Upvotes: 2

Shreyans
Shreyans

Reputation: 1061

To run the volley requests multiple times (like in a for loop) with your log output strictly following the order that you have defined you could do this-

1)put the code you have in the 'for loop' inside a runnable

Runnable runnable=new Runnable(){
    //your code here
};

2)Create a Handler anywhere before the above code using

Handler handler=new Handler();

and now put this line as the last line inside onResponse

handler.post(runnable);

3) Now your code will run in an infinite loop so you need to create an exit condition. you could create a counter variable and increment it inside onResponse. Then just put handler.post() inside a if condition checking if counter<8 or something similar.

Using a handler you can make the volley request again without incrementing the counter from onErrorResponse and can better handle request failure than using a for loop.

Also your exit condition can be some boolean you get as a response and therefore you can let the server tell you how many requests to make instead of a hardcoded fixed number.

Thirdly (and as i have mentioned before) the code that you have in the runnable before you make volley request will always be executed after the previous request is completed so you can make use of this strict ordering if you so wish.

If you have any doubts or some of the code doesnt work kindly comment so i can make the required edits.

Upvotes: 0

royB
royB

Reputation: 12977

You are creating the RequestQueue inside the for loop...

So there is no Call Queue...Move it out of the for loop

RequestQueue queue = Volley.newRequestQueue(getActivity());
for(..){
   ...
   queue.add(requestAva);
}

Upvotes: 2

Related Questions