Android開發筆記 ViewPager 巢狀 RecyclerView instantiateItem資料初始化錯位問題
阿新 • • 發佈:2019-02-07
在應用開發過程中,使用ViewPager巢狀RecyclerView實現整屏的橫滑是很常見的需求。在為ViewPager設定adapter的時候,需要重寫初始化方法,
presenter中定義一個佇列變數,
public Object instantiateItem(ViewGroup container, int position) {}來告訴ViewPager對應每個position展示什麼View,在這個方法中將
position對應的view add進container,返回該view即可。
在MVP模式的專案中,告訴Presenter該position頁需要請求的資料,將資料放入recyclerView即可。但是,在ViewPager初始化的時候,@Override public Object instantiateItem(ViewGroup container, int position) { View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.detail, null); recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); ViewGroup parent = (ViewGroup) view.getParent(); if (parent != null) { parent.removeView(view); } container.addView(view); if (mPresenter == null) { initPresenter(); } mPresenter.updateRecyclerView(pagerDataList.get(position), recyclerView); return view; }
instantiateItem()方法會連續執行position = 0 和 position = 1 兩次,當presenter需要去網路請求position = 0資料完成後,presenter持有的
recyclerView引用已經指向了position = 1的view內的recyclerView物件,資料也會被貼到position = 1的頁面裡。在viewPager的滑動過程中,每次滑動
預載入下一頁時instantiateItem只會執行一次,網路正常的情況下,不會出現錯亂問題。
解決辦法:維護一個任務佇列,在每次presenter請求資料時,將資料的標記(id)與recyclerView存入對列,資料請求回來後,判斷是否有等待的任務,有等待的
任務,則任務出隊,請求資料,給recyclerView貼資料。
public static class Task { private int id; private RecyclerView recyclerView; public int getId() { return id; } public RecyclerView getRecyclerView() { return recyclerView; } public Task (int id, RecyclerView recyclerView) { this.id = id; this.recyclerView = recyclerView; } }
presenter中定義一個佇列變數,
private Queue<Task> caCheTaskQueue = new LinkedList<Task>();
每次需要請求一個也頁面的資料的時候,判斷佇列裡有沒有快取任務,並將本次任務入隊
if (caCheTaskStack.isEmpty()) {
initRecyclerView();//請求資料並交給recyclerView初始化
}
caCheTaskStack.offer(new Task(currentPageId, recyclerView));//入隊
在initRecyclerView()網路請求回撥裡,任務出隊,再判斷是否有任務等待。caCheTaskStack.poll();//本次任務出隊
if (!caCheTaskStack.isEmpty()) {
Task task = caCheTaskStack.peek();//快取任務讀取
currentPageId = task.getId();
recyclerView = task.getRecyclerView();
initRecyclerView();//請求資料並交給recyclerView初始化
}