Android在RecyclerView上猛扑动作 [英] Android fling actions on a RecyclerView

查看:135
本文介绍了Android在RecyclerView上猛扑动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近在玩RecyclerView和Android 5+中的ViewHolder概念。适配器实现处理相当大的数据集(约6万个项目),这些数据集是通过 onBindViewHolder(...)调用从互联网上请求的。网络请求由凌空库处理,响应代表用于填充视图持有人的数据模型。



现在,当快速移动时(即以速度运动) ,而不是用户触摸设备并在屏幕上缓慢移动的滑动方式),对于适配器中的所有位置都调用 onBindViewHolder ,这不是一件好事,因为大多数视图持有者无法动画的高速可见。例如,如果用户在几秒钟内从位置5滑动到300,则大多数视图都不可读,但将调用bind方法。由于适配器从网络获取数据模型-发出了很多请求,因此大多数请求都没有用,并且空洞处理只是延迟了用户可以观察到的位置300附近的请求处理。 / p>

如何解决这个仅请求可见职位的问题?
我的第一种方法是在排球处理队列中确定请求的优先级。实际上,这并不能解决很多问题,因为每个网络请求都以不同的顺序处理。我的第二种方法是在添加新请求时取消所有现有请求。从我的角度来看,它真的不能很好地工作,从设计的角度来看,我也不喜欢这种解决方案。



我的真正问题是,您将如何处理这个问题?

解决方案

是的,我设法通过保持每个适配器位置的状态来解决问题。 RecyclerView.Adapter有两种方法,当视图大约在显示时发出信号 onViewAttachedToWindow(VH持有人) onViewDetachedFromWindow(VH持有人)



我创建了一个简单的单例类来保持每个适配器位置的状态:

  import java.util.HashSet; 
import java.util.Set;

/ **
*由fauri创建于2015年6月14日。
* /
公共类ViewHolderState {
私有静态最终ViewHolderState ourInstance = new ViewHolderState();
private Set< Integer>回收=新的HashSet<>();

私人ViewHolderState(){
}

public static ViewHolderState getInstance(){
返回ourInstance;
}

public void addRecycledView(int position){
再循环.add(position);
}

public void removeRecycledView(int position){
再循环.remove(position);
}

public boolean isViewRecycled(int position){
return recombinant.contains(position);
}

public void clearAll(){
再循环.clear();
}
}

而在适配器类中:

 私人ViewHolderState viewHolderState = ViewHolderState.getInstance(); 


@Override
public void onViewDetachedFromWindow(CardViewHolderholder){
super.onViewDetachedFromWindow(holder);
viewHolderState.addRecycledView(holder.getAdapterPosition());
}

@Override
public void onViewAttachedToWindow(CardViewHolderholder){
super.onViewAttachedToWindow(holder);
viewHolderState.removeRecycledView(holder.getAdapterPosition());
}

这只是保持每个适配器位置的状态。现在,在触发网络调用的业务逻辑中,您只需要获取单例实例并检查 isViewRecycled(int adapterPosition)。如果视图被回收,则无需进行网络调用。



当然,这是一个简单的解决方案。可以通过增加线程安全性来改进代码(即使用Collection.synchronizedSet(...)或使方法同步)或仅使用其他模式。 Java专家并没有真正挖掘单例模式。



无论如何,通常的想法是利用 onViewAttachedToWindow onViewDetachFromWindow


I was recently playing a little bit with the RecyclerView and the concept of ViewHolder's in Android 5+. The adapter implementation handles quite a large dataset (i.e ~ 60 000 items), requested from the internet upon onBindViewHolder(...) call. The network requests are handled by the volley library and the response represents the data model used to fill up the view holder.

Now when fast-flinging (i.e motion with a velocity, different than swipe where a user touches the device and moves slowly across the screen) the onBindViewHolder is called for all positions in the adapter, which is not a good thing as most of the viewholders can't be visible due to high speed of the animation. For example, if user swipes from position 5 to 300 in a matter of seconds most of the views can't be readable, yet the bind method is called. Since the adapter gets the data model from the network - a lot of requests are made, most of them are of no use, and the hole process just delays the processing of requests around position 300 which is the one that user can realy observe.

How would one approach this issue of requesting only the visible positions? My first approach was to prioritize the requests in the volley processing queue. This really didn't solve much of the problem since every network request is processed just in a different order. My second approach was to cancel all existing requests when a new one is added. It didn't work for me really well and from a design point of view I don't like this solution.

My real question is then, how would you approach this issue?

解决方案

Yes, I've managed to fix my issues by keeping the state of each adapter position. The RecyclerView.Adapter has two methods onViewAttachedToWindow(VH holder) and onViewDetachedFromWindow(VH holder) signaled when the view is about to be seen by the user or when it's removed so that the user can't see it.

I created a simple singleton class to keep the state of each adapter position:

import java.util.HashSet;
import java.util.Set;

/**
 * Created by fauri on 14/06/2015.
 */
public class ViewHolderState {
    private static final ViewHolderState ourInstance = new ViewHolderState();
    private Set<Integer> recycled = new HashSet<>();

    private ViewHolderState() {
    }

    public static ViewHolderState getInstance() {
        return ourInstance;
    }

    public void addRecycledView(int position) {
        recycled.add(position);
    }

    public void removeRecycledView(int position) {
        recycled.remove(position);
    }

    public boolean isViewRecycled(int position) {
        return recycled.contains(position);
    }

    public void clearAll() {
        recycled.clear();
    }
}

While in the adapter class:

 private ViewHolderState viewHolderState = ViewHolderState.getInstance();


 @Override
    public void onViewDetachedFromWindow(CardViewHolder holder) {
        super.onViewDetachedFromWindow(holder);
        viewHolderState.addRecycledView(holder.getAdapterPosition());
    }

    @Override
    public void onViewAttachedToWindow(CardViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        viewHolderState.removeRecycledView(holder.getAdapterPosition());
    }

This is just to keep the state of each adapter position. Now in the business logic that triggers the network calls, you will just have to get the singleton instance and check if isViewRecycled(int adapterPosition). If the view is recycled then no need to make the network call.

Of course this is a simple solution. The code can be improved by adding thread safety (i.e either use Collection.synchronizedSet(...) or make the methods synchronzied) or just use another pattern. Java guru's don't really dig the singleton pattern.

Anyway the general idea is to make use of onViewAttachedToWindow and onViewDetachFromWindow

这篇关于Android在RecyclerView上猛扑动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆