在应用开发过程中,使用ViewPager嵌套RecyclerView实现整屏的横滑是很常见的需求。在为ViewPager设置adapter的时候,需要重写初始化方法,
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>();每次需要请求一个也页面的数据的时候,判断队列里有没有缓存任务,并将本次任务入队在initRecyclerView()网络请求回调里,任务出队,再判断是否有任务等待。if (caCheTaskStack.isEmpty()) { initRecyclerView();//请求数据并交给recyclerView初始化 } caCheTaskStack.offer(new Task(currentPageId, recyclerView));//入队
caCheTaskStack.poll();//本次任务出队 if (!caCheTaskStack.isEmpty()) { Task task = caCheTaskStack.peek();//缓存任务读取 currentPageId = task.getId(); recyclerView = task.getRecyclerView(); initRecyclerView();//请求数据并交给recyclerView初始化 }