在滚动时在 recyclerview 中加载更多数据

Posted

技术标签:

【中文标题】在滚动时在 recyclerview 中加载更多数据【英文标题】:Loading more data in recyclerview on scroll 【发布时间】:2019-06-25 16:56:48 【问题描述】:

我在包含 100 个项目的列表中获取 Json 数据。我将此列表传递给 recyclerview 适配器。但我一开始只想通过 10 个项目。在用户滚动列表的 10 项之后,它应该从列表中加载更多数据。我已经实现了滚动侦听器和其他适配器。我不确定如何将 json 列表中的 10 项传递给适配器。

滚动监听器

public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener 

LinearLayoutManager layoutManager;

/**
 * Supporting only LinearLayoutManager for now.
 *
 * @param layoutManager
 */
public PaginationScrollListener(LinearLayoutManager layoutManager) 
    this.layoutManager = layoutManager;


@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) 
    super.onScrolled(recyclerView, dx, dy);

    int visibleItemCount = layoutManager.getChildCount();
    int totalItemCount = layoutManager.getItemCount();
    int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();

    if (!isLoading() && !isLastPage()) 
        if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
                && firstVisibleItemPosition >= 0
                && totalItemCount >= getTotalPageCount()) 
            loadMoreItems();
        
    



protected abstract void loadMoreItems();

public abstract int getTotalPageCount();

public abstract boolean isLastPage();

public abstract boolean isLoading();


适配器

public class PaginationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> 

private static final int ITEM = 0;
private static final int LOADING = 1;

private List<Movie> movies;
private Context context;

private boolean isLoadingAdded = false;

public PaginationAdapter(Context context) 
    this.context = context;
    movies = new ArrayList<>();


public List<Movie> getMovies() 
    return movies;


public void setMovies(List<Movie> movies) 
    this.movies = movies;


@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
    RecyclerView.ViewHolder viewHolder = null;
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());

    switch (viewType) 
        case ITEM:
            viewHolder = getViewHolder(parent, inflater);
            break;
        case LOADING:
            View v2 = inflater.inflate(R.layout.item_progress, parent, false);
            viewHolder = new LoadingVH(v2);
            break;
    
    return viewHolder;


@NonNull
private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) 
    RecyclerView.ViewHolder viewHolder;
    View v1 = inflater.inflate(R.layout.item_list, parent, false);
    viewHolder = new MovieVH(v1);
    return viewHolder;


@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) 

    Movie movie = movies.get(position);

    switch (getItemViewType(position)) 
        case ITEM:
            MovieVH movieVH = (MovieVH) holder;

            movieVH.textView.setText(movie.getTitle());
            break;
        case LOADING:

            break;
    



@Override
public int getItemCount() 

    return movies == null ? 0 : movies.size();


@Override
public int getItemViewType(int position) 
    return (position == movies.size() - 1 && isLoadingAdded) ? LOADING : ITEM;




public void add(Movie mc) 
    movies.add(mc);
    notifyItemInserted(movies.size() - 1);


public void addAll(List<Movie> mcList) 
    for (Movie mc : mcList) 
        add(mc);
    


public void remove(Movie city) 
    int position = movies.indexOf(city);
    if (position > -1) 
        movies.remove(position);
        notifyItemRemoved(position);
    


public void clear() 
    isLoadingAdded = false;
    while (getItemCount() > 0) 
        remove(getItem(0));
    


public boolean isEmpty() 
    return getItemCount() == 0;



public void addLoadingFooter() 
    isLoadingAdded = true;
    add(new Movie());


public void removeLoadingFooter() 
    isLoadingAdded = false;

    int position = movies.size() - 1;
    Movie item = getItem(position);

    if (item != null) 
        movies.remove(position);
        notifyItemRemoved(position);
    


public Movie getItem(int position) 
    return movies.get(position);



    public MovieVH(View itemView) 
        super(itemView);

        textView = (TextView) itemView.findViewById(R.id.item_text);
    



protected class LoadingVH extends RecyclerView.ViewHolder 

    public LoadingVH(View itemView) 
        super(itemView);
    




**获取 API 响应 **

private void callApi() 
    apiInterfacePages = ApiClient.getRetrofit().create(APIInterface.class);
    Call<CamerasItem> camerasCall = apiInterfacePages.getCameras();
    camerasCall.enqueue(new Callback<CamerasItem>() 
        @Override
        public void onResponse(Call<CamerasItem> call, Response<CamerasItem> response) 

            CamerasItem camerasItem = response.body();
            itemList = new ArrayList<>();
            itemList = camerasItem.getItems();
            Log.i("Item", "" + getChannel().getName());

            for (int i = 0; i < itemList.size(); i++) 

                if (itemList.get(i).getCategory().equals(getChannel().getName()))
                    if (!itemList.get(i).getUrlMjpeg().endsWith("=mediaRedirect")) 
                        String videoUrl = itemList.get(i).getUrlMjpeg();
                        String imageUrl = itemList.get(i).getThumbnail();
                        String name = itemList.get(i).getName();
                        String city = itemList.get(i).getCity();
                        String flag = itemList.get(i).getFlag();
                        String country=  itemList.get(i).getCountry();
                        modelList.add(new MyModel(videoUrl, imageUrl, name, city, flag,country));
                    

                
        

        @Override
        public void onFailure(Call<CamerasItem> call, Throwable t) 
            Log.i("Item", "" + t.getMessage());

        
    );

那么现在如何第一次将 10 个项目传递给 recyclerview,并在每次滚动时传递 10 个项目。

【问题讨论】:

【参考方案1】:

您必须在定义Recyclerview 的活动的xml 中设置Progressbar。 loadThumbnail 是一个下载缩略图的函数。它只是给向下滚动一点延迟。现在适配器类的完整代码如下

public class CamerasAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> 

private List<MyModel> list;
private Activity mActivity;
private static final int TYPE_VIDEO = 0, TYPE_ADD = 1;
private static final int PAGE_LIMIT = 5;
private int mCurrentLimit = PAGE_LIMIT;
private boolean mIsLoading;
RelativeLayout mLoaderProgress;

public CamerasAdapter(FragmentActivity activity, RelativeLayout loaderLayout) 
    mActivity = activity;
    mLoaderProgress = loaderLayout;


@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) 
    View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.li_web_cam_view, viewGroup, false);
    return new CamsViewHolder(itemView);


@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) 
    if (mCurrentLimit == (i + 1) && mCurrentLimit <= list.size() && !mIsLoading) 
        mLoaderProgress.setVisibility(View.VISIBLE);
        mIsLoading = true;
        loadThumbnail(0, i + 1);
     else 
        //do nothing
    
    ((CamsViewHolder) viewHolder).onBindData(mActivity, list.get(i), i);
    ((CamsViewHolder) viewHolder).emptyView.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            itemClickListner.onClick(i, ((CamsViewHolder) viewHolder).tvCamName, list.get(i));
        
    );


private void loadThumbnail(final int count, int position) 
    try 
        if (count > 2 || position >= list.size()) 
            new Handler().postDelayed(new Runnable() 
                @Override
                public void run() 
                    mIsLoading = false;
                    mCurrentLimit = mCurrentLimit + PAGE_LIMIT;
                    notifyItemChanged(position - count);
                    mLoaderProgress.setVisibility(View.GONE);
                    return;
                
            , 2000);

         else 
            if (list.get(position) == null) 
                loadThumbnail(count, position + 1);
             else 
                Glide.with(mActivity).load(list.get(position).getImage_url()).downloadOnly(new SimpleTarget<File>() 
                    @Override
                    public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) 
                        loadThumbnail((count + 1), (position + 1));
                    

                    @Override
                    public void onLoadFailed(Exception e, Drawable errorDrawable) 
                        loadThumbnail((count + 1), (position + 1));
                    
                );
            
        
     catch (Exception e) 
        e.printStackTrace();
        mLoaderProgress.setVisibility(View.GONE);
        mIsLoading = false;
    



@Override
public int getItemCount() 
    return mCurrentLimit <= list.size() ? mCurrentLimit : list.size();


public void setData(List<MyModel> dataList) 
    this.list = dataList;
    notifyDataSetChanged();


ItemClickListner itemClickListner;

public void setListener(ItemClickListner listener) 
    itemClickListner = listener;


ProgressLoadListener progressLoadListener;

public void setProgressLoadListener(ProgressLoadListener listener) 
    progressLoadListener = listener;



xml 文件的代码

<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_
    android:visibility="gone"
    android:layout_
    android:layout_above="@+id/loader_progress_bar_layout"
    android:background="#f5f5f5"
    android:layout_gravity="center" />

<RelativeLayout
    android:layout_
    android:layout_
    android:layout_alignParentBottom="true"
    android:id="@+id/loader_progress_bar_layout"
    android:visibility="gone"
    android:background="#fff"
    >
    <ProgressBar
        android:id="@+id/progress_bar_loader"
        android:layout_
        android:layout_
        android:layout_centerHorizontal="true"
        android:layout_gravity="center" />

</RelativeLayout>

使用适配器初始化 Recyclerview

public class Main2Activity extends AppCompatActivity 

RecyclerView recyclerView;
RelativeLayout layoutProgressBar;
CamerasAdapter adapter;
List<Item> itemList;
LinearLayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    layoutProgressBar = findViewById(R.id.loader_progress_bar_layout);
    recyclerView = findViewById(R.id.recycler_view);
    adapter = new CamerasAdapter(getActivity(), loaderLayout);
    mLayoutManager = new LinearLayoutManager(getActivity());
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.setAdapter(adapter);

    adapter.setProgressLoadListener(new ProgressLoadListener() 
        @Override
        public void loadProgressBar() 
            layoutProgressBar.setVisibility(View.VISIBLE);
        
    );
    adapter.setData(setAdaperData());



public List<MyModel> setAdaperData() 
    List<MyModel> modelList = new ArrayList<>();
    /*addItemsto list*/
    return modelList;



【讨论】:

以上是关于在滚动时在 recyclerview 中加载更多数据的主要内容,如果未能解决你的问题,请参考以下文章

向下滚动然后再次向上滚动后,recyclerview 项目之间出现间隙。请看详情

如何使用 StaggeredGridLayoutManager 在 recyclerview 中实现无限滚动(分页)

使用 Glide 和 RecyclerView 上下滚动时图像消失,图像之间的空间增加

为啥在我第一次单击按钮时在我的 RecyclerView 中调用绑定?

将物品贴在recyclerview的顶部

如何在活动启动时在recyclerview中显示已选中的复选框(多对多关系)