2016-02-12 68 views
2

我是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_FETCHEDFLAG_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的順序。如果您需要任何其他信息,請告訴我。

謝謝。

回答

2

這是如何避免兩個請求的競爭條件一般工作。你應該使用回調。你的onResponse方法的實現是回調,因爲這些方法在一個請求完成後被調用。響應處理在UI線程上正常工作?所以響應可以只處理一個由其他。 這意味着你只需要在那裏維持秩序。在獲得一個響應後提取您想要完成的工作。您需要一些布爾標誌來指示您的請求是否已完成。僞代碼看起來像這樣:

request1Done = false; 
request2Done = false; 
doRequest1(); 
doRequest2(); 
onResponse1() { 
    doWorkForRequest1(); // always start handling the response 
    request1Done = true; 
    if (request2Done) { // if this is true, request2 was faster than request1 
     doWorkForRequest2(); 
    } 
}; 
onResponse2() { 
    request2Done = true; 
    if (request1Done) { // request1 did its work, no its request2's turn 
     doWorkForRequest2(); 
    } 
};  

所以基本上你應該修復你的onReponse方法。希望這會幫助你。 :)

+1

嗯,我最初認爲'onResponse'代碼在工作線程上工作,然後它運行主UI線程上的所有UI調用。我完全錯了!感謝您的回答。我實現了一些比較簡單的技術來防止競爭條件,在這種情況下,我創建了一個名爲'setAdapters'的方法,並在兩個'onResponse'方法中調用了它。 'setAdapters'方法代碼只在'request1 && request2'爲真時運行,以便我可以確定'ArrayLists'已經被填充。再次感謝 :) –