Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make concurrent GET calls using Volley?

I have 3 API GET calls. The problem I'm facing with my approach is, the app is able to fetch the data successfully from two APIs and I'm able to display it on UI as well. But, for the third API call, due to the below error, the data that is being shown previously disappears which is bad.

D/Volley: [380] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://example.com/api/search/getTwitterData?limit=10&tag=JavaScript 0x865f5dc2 NORMAL 3> [lifetime=6683], [size=10543], [rc=200], [retryCount=0]

How do I make concurrent API GET calls using Volley without losing the data on UI. Could anyone please guide me?

Here are excerpts from my code.

public class StaggeredSearchActivity extends AppCompatActivity {

    ...

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

        requestQueue = Volley.newRequestQueue(this);

        Intent intent = getIntent();
        String searchText = intent.getStringExtra("searchText");

        // Three concurrent API GET Calls  
        getMediumData(searchText);
        getExampleData(searchText);
        getGoogleData(searchText);

        recyclerView = findViewById(R.id.staggered_recycler_view);
        staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);
    }

    ArrayList<StaggeredCustomCard> dataset = new ArrayList<>();

    private void getMediumData(String searchText) {
        progressBar = findViewById(R.id.progressBar);
        progressBar.setVisibility(View.VISIBLE);

        String url = UrlConstants.getUrl() + searchText;

        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
                (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

                    @Override
                    public void onResponse(JSONObject response) {
                        try {
                            progressBar.setVisibility(View.INVISIBLE);
                            JSONArray array = response.getJSONArray("mediumposts");

                            ...

                            dataset.add(new StaggeredCustomCard(user, userpost, postdate));
                            }
                            staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
                            recyclerView.setAdapter(staggeredGridAdapter);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        // TODO: Handle error
                        progressBar.setVisibility(View.INVISIBLE);
                    }
                });

        jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
                DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        requestQueue.add(jsonObjectRequest);
    }

    private void getExampleData(String searchText) {

        ...

        JsonArrayRequest jsonArrayRequest = new JsonArrayRequest
                (Request.Method.GET, url, null, new Response.Listener<JSONArray>() {

                    @Override
                    public void onResponse(JSONArray response) {
                        try {
                            ...
                            dataset.add(new StaggeredCustomCard(user, userpost, postdate));
                                staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
                                recyclerView.setAdapter(staggeredGridAdapter);
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        ...
                    }
                });

        jsonArrayRequest.setRetryPolicy(new DefaultRetryPolicy(
                DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        requestQueue.add(jsonArrayRequest);
    }

    private void getGoogleData(String searchText) {
        ...

        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
                (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

                    @Override
                    public void onResponse(JSONObject response) {
                        ...

                        dataset.add(new StaggeredCustomCard(user, userpost, postdate));

                            }
                            staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
                            recyclerView.setAdapter(staggeredGridAdapter);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }

                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        ...
                    }
                });

        jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(
                DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 15,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        requestQueue.add(jsonObjectRequest);
    }
}
like image 708
coderpc Avatar asked Sep 16 '19 16:09

coderpc


2 Answers

The problem is that you are initializing Adapter every time that's why your data will be lost once a new API call. I prefer below approach so that can help you, Add Data in ArrayList and notify adapter,

Add this line in onCreate,

staggeredGridAdapter = new StaggeredGridAdapter(StaggeredSearchActivity.this, dataset);
recyclerView.setAdapter(staggeredGridAdapter);

Changes in API Callback Response :

                             ...

dataset.add(new StaggeredCustomCard(user, userpost, postdate));

After loop add below line

staggeredGridAdapter.notifyDataSetChanged();

Changes in Adapter

 private ArrayList<StaggeredCustomCard> dataSet;
        private Context context;

        public MyAdapter(ArrayList<StaggeredCustomCard> dataSet, Context context) {
            this.data = data;
            this.context = context;
        }

Note : Don't create new object on adapter.

like image 154
Kintan Patel Avatar answered Sep 18 '22 00:09

Kintan Patel


The approach just doesn't make a lot of sense. Once you get a response from one of the three endpoints, you seem to create a new Adapter and attach it to the recycler with a random "notifyDataSetChanged" every time...

  1. Maybe look at using a ViewModel with a service layer and network layer that deal with the business login.
  2. The ViewModel updates/posts a MutableLiveData> when a callback from one of the Network methods responds from the endpoints...merging the three pieces of data.
  3. The activity just observes the ViewModel's MutableLiveData and uses a DiffUtil to update the look/cards in the recycler.

enter image description here

like image 28
Jcov Avatar answered Sep 19 '22 00:09

Jcov