我是Android Development
的新手,我正在嘗試開發我的第一款Android應用程序,它使用Android Volley
從部分public APIs
獲取數據。避免在Android應用程序中獲取競速條件在Android應用程序中排球條件
我正在使用singleton Volley Request Queue
,它在啓動器活動中初始化。當我將RecyclerView
適配器設置在Volley's JsonObjectRequest
的內部時,我成功地能夠解析JSON內容並將它們顯示在Fragment layout/view (uses RecyclerView & CardView)
上。
以下代碼顯示數據,但遭受時間競爭條件。 注意:RvJoiner是一個庫,它合併多個適配器,並通過FIRST COME FIRST SERVE基礎訂購單個適配器。
我的片段類如下:
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.recylcer_main, container, false);
ParseJSON parseJSON = new ParseJSON(v);
parseJSON.makeRequest1();
parseJSON.makeRequest2();
return v;
}
}
我ParseJSON類是如下
public class ParseJSON {
private static final String URL1 = "some url";
private static final String URL2 = "some other url";
private static final String TAG = "ParseJSON";
private RequestQueue requestQueue;
private boolean FLAG_REQUEST1_FETCHED;
private boolean FLAG_REQUEST2_FETCHED;
private ArrayList<status1> status1ArrayList;
private ArrayList<status2> status2ArrayList;
private Context context;
private RvJoiner rvJoiner;
private View view;
ProgressDialog pd;
ParseJSON (View v){
this.view= v;
this.context=v.getContext();
pd = ProgressDialog.show(v.getContext(), "Please Wait", "Getting Data from APIs", true);
requestQueue = AppController.getInstance(v.getContext()).getRequestQueue();
rvJoiner = new RvJoiner();
}
public void makeRequest1() {
JsonObjectRequest request1 = new JsonObjectRequest(Request.Method.GET, URL1,
null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
/* Parsing Stuff and storing it in status1ArrayList */
FLAG_REQUEST1_FETCHED=true;
Status1Adapter status1Adapter = new Status1Adapter(status1ArrayList);
RecyclerView recList = (RecyclerView) view.findViewById(R.id.cardList);
recList.setLayoutManager(new LinearLayoutManager(context));
rvJoiner.add(new JoinableAdapter(status1Adapter));
recList.setAdapter(rvJoiner.getAdapter());
pd.dismiss();
}
} catch (JSONException e) {}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {}
});
AppController.getInstance(context).addToRequestQueue(request1);
}
public void makeRequest2() {
JsonObjectRequest request2 = new JsonObjectRequest(Request.Method.GET, URL2,
null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
/* Parsing stuff and storing it inside ArrayList status2ArrayList */
FLAG_REQUEST2_FETCHED=true;
Status2Adapter status2Adapter = new Staus2Adapter(status2ArrayList);
RecyclerView recList = (RecyclerView) view.findViewById(R.id.cardList);
recList.setLayoutManager(new LinearLayoutManager(context));
rvJoiner.add(new JoinableAdapter(status2Adapter));
}
} catch (JSONException e) {}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {}
});
AppController.getInstance(context).addToRequestQueue(request2);
}
public boolean isStatusFetched(){
return FLAG_REQUEST1_FETCHED && FLAG_REQUEST2_FETCHED;
}
public ArrayList<status1> getstatus1ArrayList() {
return status1ArrayList;
}
public ArrayList<status2> getstatus2ArrayList() {
return status2ArrayList;
}
}
在上面的代碼中,我有一個爭用條件。由於Volley
網絡通話本質上是異步的,因此我無法控制哪個請求會先完成並顯示在我的Fragment CardView
上。 (即rvJoiner.add()
中的任何一個請求都可以先執行)
我想讓UI保持一致,即我希望先將Request1適配器添加到RvJoiner,然後再添加Request2。
如果可能,我想移動所有設置適配器並將它們從JsonObjectRequest連接到我的Fragment的onCreateView方法的代碼。所以,通過這種方式,我可以控制適配器的順序。但是,我需要一種方法,通過isStatusFetched
方法不斷檢查FLAG_REQUEST1_FETCHED
和FLAG_REQUEST2_FETCHED
的值。
代碼的片段類將是
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.recylcer_main, container, false);
ParseJSON parseJSON = new ParseJSON(v);
parseJSON.makeRequest1();
parseJSON.makeRequest2();
while(!parseJSON.isDataFetched()){
/* I want to wait here till both status1ArrayList and status2ArrayList gets populated with data in ParseJSON. In this way I can control the order in which adapters are added inside RvJoiner. If I don't wait here I will get NullPointerException on runtime since Volley calls are asynchronous and getStatus1ArrayList/getStatus2ArrayList will most probably return null. But how to wait here without consuming too much CPU power? */
}
ArrayList<status1> status1ArrayList = parseJSON.getstatus1ArrayList();
ArrayList<status2> status2ArrayList = parseJSON.getstatus2ArrayList();
Status1Adapter status1Adapter = new Status1Adapter(status1ArrayList);
Status2Adapter status2Adapter = new Status2Adapter(status2ArrayList);
RecyclerView recList = (RecyclerView) v.findViewById(R.id.cardList);
recList.setLayoutManager(new LinearLayoutManager(v.getContext()));
RvJoiner rvJoiner = new RvJoiner();
/* Problem solved as I'm adding adapters in the order I want */
rvJoiner.add(new JoinableAdapter(status1Adapter));
rvJoiner.add(new JoinableAdapter(status2Adapter));
recList.setAdapter(rvJoiner.getAdapter());
return v;
}
}
的一個解決方案可使用回調。我讀了一些關於他們的地方,但我不確定它是否解決了我在維持秩序的同時多次請求的問題。
另一解決方案是限制我的排球隊列處理僅在一個時間一個請求,但將增加抓取和服務數據所花費的時間。這是我的最後一個選擇。
我幾乎沒有想法,並希望有人來幫助我,這樣我就可以控制設置適配器並保持一致的UI的順序。如果您需要任何其他信息,請告訴我。
謝謝。
嗯,我最初認爲'onResponse'代碼在工作線程上工作,然後它運行主UI線程上的所有UI調用。我完全錯了!感謝您的回答。我實現了一些比較簡單的技術來防止競爭條件,在這種情況下,我創建了一個名爲'setAdapters'的方法,並在兩個'onResponse'方法中調用了它。 'setAdapters'方法代碼只在'request1 && request2'爲真時運行,以便我可以確定'ArrayLists'已經被填充。再次感謝 :) –