我有一个片段,一旦加载,我就会在其中获取一些博客。我在这里进行分页,所以,我最初为 page=1 加载数据。
我还实现了一个 scrollListener ,它在用户向下滚动时进行后续 API 调用以加载更多博客。每次进行新调用时,我都会在recyclerview 的末尾添加一个progressBar。代码如下。
正在发生的问题是,我得到了多个进度对话框,如图所示。此外,即使页码不断增加,它也会不断加载更多数据。不添加行号(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);
// BlogsRecyclerViewScrollListener
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>
// BlogsRecyclerViewAdapter
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;
}
}