Android 在无尽的recyclerview分页中获取多个ProgressBar

Android 在无尽的recyclerview分页中获取多个ProgressBar,android,android-recyclerview,pagination,progress-bar,endlessscroll,Android,Android Recyclerview,Pagination,Progress Bar,Endlessscroll,我有一个片段,在它加载后,我会立即获取一些博客。我在这里进行分页,因此,我首先加载page=1的数据 我还实现了一个scrollListener,它在用户向下滚动时进行后续API调用以加载更多博客。每次打新电话时,我都会在recyclerview的末尾添加一个progressBar。代码如下所示 发生的问题是,我得到了多个progressdialogs,如图所示。而且,即使页码不断增加,它也会不断加载更多数据。如果不添加行号1-4,就不会出现无止境的数据。我就是不明白 我只是不明白代码的问题。只

我有一个片段,在它加载后,我会立即获取一些博客。我在这里进行分页,因此,我首先加载page=1的数据

我还实现了一个scrollListener,它在用户向下滚动时进行后续API调用以加载更多博客。每次打新电话时,我都会在recyclerview的末尾添加一个progressBar。代码如下所示

发生的问题是,我得到了多个progressdialogs,如图所示。而且,即使页码不断增加,它也会不断加载更多数据。如果不添加行号1-4,就不会出现无止境的数据。我就是不明白

我只是不明白代码的问题。只要调用新的API,我就想在recyclerview的末尾添加progressdialog

    BlogsRecyclerViewAdapter adapter;
    ArrayList<BlogResponse> blogsList;
//片段中的scrollListener代码

    blogsList = new ArrayList<>();
    adapter = new BlogsRecyclerViewAdapter(getContext(), blogsList);
    blogsRecyclerView.setAdapter(adapter);
    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
    blogsRecyclerView.setLayoutManager(linearLayoutManager);

    scrollListener = new BlogsRecyclerViewScrollListener(linearLayoutManager) {
        @Override
        public boolean onLoadMore(final int page, int totalItemsCount, RecyclerView view) {

            blogsList.add(null);  //line-1
            adapter.notifyItemInserted(blogsList.size()-1); //line-2

            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    //   remove progress item
                    blogsList.remove(blogsList.size() - 1); //line-3
                    adapter.notifyItemRemoved(blogsList.size()); //line-4
                    fetchBlogs(page);
                }
            }, 2000); //time 2 seconds
            return true; // ONLY if more data is actually being loaded; false otherwise.
        }
    };
    fetchBlogs(1);
   blogsRecyclerView.addOnScrollListener(scrollListener);
//BlogsRecycleViewScrollListener

 public abstract class BlogsRecyclerViewScrollListener extends RecyclerView.OnScrollListener{
private int visibleThreshold = 3;

private int currentPage = 1;

private int previousTotalItemCount = 0;

private boolean loading = true;

private int startingPageIndex = 1;

RecyclerView.LayoutManager mLayoutManager;

public BlogsRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
    this.mLayoutManager = layoutManager;
}

public int getLastVisibleItem(int[] lastVisibleItemPositions) {
    int maxSize = 0;
    for (int i = 0; i < lastVisibleItemPositions.length; i++) {
        if (i == 0) {
            maxSize = lastVisibleItemPositions[i];
        }
        else if (lastVisibleItemPositions[i] > maxSize) {
            maxSize = lastVisibleItemPositions[i];
        }
    }
    return maxSize;
}

@Override
public void onScrolled(RecyclerView view, int dx, int dy) {
    int lastVisibleItemPosition = 0;
    int totalItemCount = mLayoutManager.getItemCount();

    lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();

    if (totalItemCount < previousTotalItemCount) {
        this.currentPage = this.startingPageIndex;
        this.previousTotalItemCount = totalItemCount;
        if (totalItemCount == 0) {
            this.loading = true;
        }
    }

    if (loading && (totalItemCount > previousTotalItemCount)) {
        loading = false;
        previousTotalItemCount = totalItemCount;
    }

    if (!loading && (lastVisibleItemPosition + visibleThreshold) >= totalItemCount) {
        currentPage++;
        onLoadMore(currentPage, totalItemCount, view);
        loading = true;
    }
}
    public void resetState() {
        this.currentPage = this.startingPageIndex;
        this.previousTotalItemCount = 0;
        this.loading = true;
    }

    public abstract boolean onLoadMore(int page, int totalItemsCount, 
    RecyclerView view);
}
//获取博客方法

     private void fetchBlogs(final int page) {

        apiServiceWithoutVersion.getBlogs(String.valueOf(page))
        .enqueue(new 
        Callback<ArrayList<BlogResponse>>() {
        @Override
        public void onResponse(Call<ArrayList<BlogResponse>> call, 
        Response<ArrayList<BlogResponse>> response) {
            if(response.isSuccessful()){  
                for(BlogResponse blogResponse: response.body()){
                    blogsList.add(blogResponse);
                }
                adapter.notifyDataSetChanged();
            }else{
                //some code to show error
            }
        }

        @Override
        public void onFailure(Call<ArrayList<BlogResponse>> call, Throwable t) {
            //some code to show failure
        }
    });
}
//item_loading.xml

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout 
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical">
    <ProgressBar
        android:id="@+id/progress_bar_at_bottom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />
 </LinearLayout>
//BlogsRecycleServiceAdapter

public class BlogsRecyclerViewAdapter extends 
RecyclerView.Adapter<RecyclerView.ViewHolder> {

Context mContext;
ArrayList<BlogResponse> mObjects;
ArrayList<BlogResponse> mFilteredObjects;
onItemClickListener mListener;

private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;

public void setOnItemClickListener(onItemClickListener listener){
    mListener = listener;
}

public BlogsRecyclerViewAdapter(Context context, ArrayList<BlogResponse> objects){
    mContext = context;
    mObjects = objects;
    mFilteredObjects = objects;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder holder = null;
    if(viewType==VIEW_ITEM) {
        View view = View.inflate(mContext, R.layout.list_item_blogs_recycler_view, null);
        holder = new BlogViewHolder(view);
    }else{
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_loading, parent, false);

        holder = new ProgressViewHolder(v);
    }
    return holder;
}

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

    if(holder instanceof BlogViewHolder){
        //code for blogs

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onItemClick(position);
            }
        });
    }else{
        ((ProgressViewHolder)holder).progressBar.setIndeterminate(true);
    }

}

@Override
public int getItemCount() {
    return mFilteredObjects.size();
}

private class BlogViewHolder extends RecyclerView.ViewHolder {

    public BlogViewHolder(View itemView) {
        super(itemView);
        // Code for blogs
    }
}

private class ProgressViewHolder extends RecyclerView.ViewHolder {
    public ProgressBar progressBar;
    public ProgressViewHolder(View v) {
        super(v);
        progressBar = v.findViewById(R.id.progress_bar_at_bottom);
    }
}

public interface onItemClickListener{
    void onItemClick(int position);
}


@Override
public int getItemViewType(int position) {
    return mObjects.get(position)!=null? VIEW_ITEM: VIEW_PROG;
}

}

在您的情况下,有些软件会在收到您的响应之前多次调用您的onLoadMore。因此,它会在列表中添加null,以便在列表中显示多个progressBar


因此,您必须在滚动更多后进行调试。

您可以尝试检查当前是否正在加载数据

if(blogsList.get(blogsList.size() - 1) != null) {
    blogsList.add(null);  //line-1
    adapter.notifyItemInserted(blogsList.size()-1); //line-2

    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            //   remove progress item
            blogsList.remove(blogsList.size() - 1); //line-3
            adapter.notifyItemRemoved(blogsList.size()); //line-4
            fetchBlogs(page);
        }
    }, 2000); //time 2 seconds
}

根据列表项视图高度更改或调整此visibleThreshold。您可以查看链接以了解更多详细信息。这将帮助您停止scroll上的多个API调用。

谢谢您的回答。它确实在某种程度上解决了这个问题,因为我现在没有得到多个进度对话框,但仍然得到没完没了的API调用。无法识别最后一次呼叫/页面。我认为在添加和删除项目的同时,如果需要,检查是否会获取moe数据时,会出现一些问题!正在加载&lastVisibleItemPosition+visibleThreshold>=totalItemCount@Yesha我认为最好添加一些用于跟踪api调用执行的布尔变量,并在启动调用时将其设置为true,在公共void onResponse中设置为false。。。如果此时情况属实,只需忽略onScrolled内容,而不要在onLoadMore上执行..问题可能出在这一行:int totalItemCount=mLayoutManager.getItemCount;将空项添加到列表时,这将为真:totalItemCount>previousTotalItemCount。您可以尝试将ProgressBar作为一个单独的视图添加到您的RecyclerView下面,然后将Recycler绑定到该视图,并在未加载数据时使其消失。因此,您不必将null项添加到列表中。我也不明白为什么要使用postDelayed..2000,并在执行api调用之前等待2秒钟。您添加progressBar,然后在2秒后删除它,然后启动api调用?您应该显示PB,然后在onResponse方法上执行api调用并隐藏PB。另外一件您不需要使用foreach添加新数据的事情是,您可以使用blogsList.addAllresponse.body;我遵循了相同的链接。还是搞不清楚这个问题
// The minimum number of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 0;