如何使用Volley进行并发GET调用?

时间:2019-09-16 16:43:30

标签: java android asynchronous android-volley

我有3个API GET调用。我使用的方法面临的问题是,该应用程序能够从两个API成功获取数据,并且也能够在UI上显示数据。但是,对于第三次API调用,由于以下错误,先前显示的数据会消失,这很糟糕。

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]

如何使用Volley进行并发API GET调用而又不丢失UI上的数据。有人可以指导我吗?

这是我代码的节选。

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);
    }
}

输出

Volley GET API calls

5 个答案:

答案 0 :(得分:3)

问题在于,每次都要初始化Adapter,这就是为什么一旦调用新的API就会丢失数据。我更喜欢以下方法,以便为您提供帮助, 在ArrayList中添加数据并通知适配器,

将此行添加到onCreate中,

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

API回调响应中的更改:

                             ...

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

循环后在行下方添加

staggeredGridAdapter.notifyDataSetChanged();

适配器的更改

 private ArrayList<StaggeredCustomCard> dataSet;
        private Context context;

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

注意:不要在适配器上创建新对象。

答案 1 :(得分:2)

这种方法没有多大意义。 从三个端点之一获得响应后,您似乎每次都将创建一个新的适配器,并使用随机的“ notifyDataSetChanged”将其附加到回收站...

  1. 也许会考虑将ViewModel与用于处理业务登录的服务层和网络层一起使用。
  2. 当来自网络方法之一的回调从端点响应时,ViewModel更新/发布了MutableLiveData>,并合并了三个数据。
  3. 该活动仅观察ViewModel的MutableLiveData,并使用DiffUtil更新回收器中的外观/卡片。

enter image description here

答案 2 :(得分:2)

最好的方法是在onCreate方法的StaggeredSearchActivity中注册LiveData并像您一样监听数据库更改。在每个成功响应中,将其结果保存到不带LiveData的db中。 onCreate方法中的LiveData将被触发。

   @Override


  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

  ViewModel viewModel = ViewModelProviders.of(this, factory).get(ViewModel.class);
            viewModel.getEntity().observe(this, entity -> {
                if (entity != null) {
                    adapter.notifyDataSetChanged(entity );

                }
            });

    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) {
                        StaggeredCustomCardDAO.insert();
                        // TODO just insert to dataBase
                    }

                }, 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 {

                            // TODO just insert to dataBase
                          StaggeredCustomCardDAO.insert();
                        } 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) {

                        // TODO just insert to dataBase
StaggeredCustomCardDAO.insert();
                    }
                }, 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);


    }


    class ViewModel extends androidx.lifecycle.ViewModel {


        private LiveData<StaggeredCustomCard> entity;


        public ViewModel(Repository repository) {
            entity = repository.getNetworkData();
        }


        public LiveData<StaggeredCustomCard> getEntity() {
            return entity;
        }
    }

    class Repository {

        LiveData<StaggeredCustomCard> getNetworkData() {

            LiveData<StaggeredCustomCard> localeData =  StaggeredCustomCardDAO .getLocaleData();//... todo Read from data base
            return localeData;
        }
    @Dao
    public interface StaggeredCustomCardDAO {
        @Query("Select * from tbl_staggeredCustomCard ")
        LiveData<StaggeredCustomCard> getLocaleData();

        @Insert(onConflict = OnConflictStrategy.REPLACE)
        void insert(List<StaggeredCustomCard> items);

    }
    }

答案 3 :(得分:0)

由于该错误,数据不应消失。首先,我建议您检查一下是否清除数据集,或者重新创建屏幕。

第二,我建议您离开Volley,因为它已经过时,需要大量关注细节的现代技术库已经过时了。使用Retrofit-这是一个现代,功能强大且得到社区认可的图书馆。使用它,您可以确保要异步的所有请求都是异步的,并且所有响应都得到了很好的处理。

我还建议您不要在每次加载数据时都创建适配器,而是使用一个适配器并向其中添加数据,它们使用notifyDataSetChanged()重新加载相关数据列表。

答案 4 :(得分:0)

第一种方法:首先,我建议您创建一个中央请求队列。

public class AppController extends Application {
    public static final String TAG = AppController.class
            .getSimpleName();
    private RequestQueue mRequestQueue;

    private static AppController mInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized AppController getInstance() {
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }

        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

然后将所需的请求添加到队列中

// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq);

第二种方式: 创建一个通用Volley类和一个接口,使用该接口获取成功和失败响应。

第1步创建一个单独的Volley类 步骤2创建一个接口,用于访问截击类的响应 步骤3为该类创建新对象并发送所需的参数 新的PostVolleyJsonRequest(TestVolley.this,TestVolley.this(interfcae),“ Submit”,url,params);

类的上下文 发送成功和失败响应的界面 确定成功的请求类型 网址(必填) 不需要GET的参数(可选) 普通排球课

public class PostVolleyJsonRequest {
private String  type;
private Activity act;
private VolleyJsonRespondsListener volleyJsonRespondsListener;
private String networkurl;
private JSONObject jsonObject = null;
private JSONObject params;


public PostVolleyJsonRequest(Activity act, VolleyJsonRespondsListener volleyJsonRespondsListener, String type, String netnetworkUrl,JSONObject params) {
    this.act = act;
    this.volleyJsonRespondsListener = volleyJsonRespondsListener;
    this.type = type;
    this.networkurl = netnetworkUrl;
    this.params = params;
    sendRequest();
}

private void sendRequest() {

    Log.d("url", "url" + networkurl);
    JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.POST,networkurl,params,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    Log.e("response", "response " + response);
                    volleyJsonRespondsListener.onSuccessJson(response, type);
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    try {
                        NetworkResponse response = error.networkResponse;
                        Log.e("response", "response " + response);
                        if (response != null) {
                            int code = response.statusCode;

                            String errorMsg = new String(response.data);
                            Log.e("response", "response" + errorMsg);
                            try {
                                jsonObject = new JSONObject(errorMsg);
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                            String msg = jsonObject.optString("message");
                            volleyJsonRespondsListener.onFailureJson(code, msg);
                        } else {
                            String errorMsg = error.getMessage();
                            volleyJsonRespondsListener.onFailureJson(0, errorMsg);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });

    jsObjRequest.setRetryPolicy(new DefaultRetryPolicy(
            600000,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
            DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

    RequestQueue requestqueue = Volley.newRequestQueue(act);
    requestqueue.add(jsObjRequest);

}
}

Use the interface to get responds message

public interface VolleyJsonRespondsListener {

public void onSuccessJson(JSONObject result, String type);
public void onFailureJson(int responseCode, String responseMessage);
}

在您要添加多个请求的班级中

public class TestVolley extends AppCompatActivity implements VolleyJsonRespondsListener{

//Your class code goes here


//network request

try {
        //parameters 
        //Context,Interface,Type(to indentify your responds),URL,parameter for your request 

        //request 1
        new PostVolleyJsonRequest(TestVolley.this, TestVolley.this, "Submit", url, params);

        //request 2
        new PostVolleyJsonRequest(TestVolley.this, TestVolley.this, "AccessData", url_2, params_2);




 } catch (Exception e) {

 e.printStackTrace()
 }

 //Methods from Interface

  @Override
public void onSuccessJson(JSONObject result, String type) {

   //Based on the Type you send get the responds and parse it 
    switch (type) {
        case "Submit":
            try {
                parseSubmit(result);
            } catch (Exception e) {