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