如何在Retrofit 2.0中处理分页/加载更多内容?

时间:2018-08-13 12:12:54

标签: android pagination gson retrofit

我还没有找到适当的示例,说明如何在向下滚动RecyclerView时使应用程序从翻新onResponse中加载更多项目。

这是我如何装载拳头20件物品的方法:

List<ModelPartners> model = new ArrayList<>();

Call<ResponsePartners> call = ApiClient.getRetrofit().getPartnerList(params);
call.enqueue(this);

我的RecyclerView

PartnersAdapter adapter = new PartnersAdapter(getContext(), recyclerView, model);
recyclerView.setAdapter(adapter);

这是我的改造onResponse

@Override
    public void onResponse(Call<ResponsePartners> call, Response<ResponsePartners> response) {
        if (getActivity() != null && response.isSuccessful()) {
            List<ModelPartners> body = response.body().getData();
            //Rest of the code to add body to my Adapter and notifyDataSetChanged
            }
        }

我的问题是,每次我添加滚动加载更多项目的方法时,onResponse会一直加载直到最后一页。即使我将loading设置为 false

有人可以显示如何在翻新中正确使用分页吗?您与Retrofit一起使用了哪些库,或向我展示了如何使用它?预先谢谢你

2 个答案:

答案 0 :(得分:3)

您需要三件事来实现这一目标,您需要:

  1. 您需要一个onscroll侦听器以访问回收者视图。
  2. 您需要一种将新项目添加到回收站适配器的方法
  3. 您需要呼叫分页端点

假设您在服务器上拥有这样的模型

public class PagedList<T> {

    private int page = 0;
    private List<T> results = new ArrayList<>();
    private int totalResults = 0;
    private int totalPages = 0;

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public List<T> getResults() {
        return results;
    }

    public void setResults(List<T> results) {
        this.results = results;
    }

    public int getTotalResults() {
        return totalResults;
    }

    public void setTotalResults(int totalResults) {
        this.totalResults = totalResults;
    }

    public int getTotalPages() {
        return totalPages;
    }

    public void setTotalPages(int totalPages) {
        this.totalPages = totalPages;
    }
}

您的OnScroll侦听器:- 在您的活动中,这就是您想要的,所以在活动中添加第二种方法

public void onCreate(Bundle savedInstance) {

    // setup your view components
    // ...

    // get the layout manager
    LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

    // rest endpoint
    apiEndpoint = retrofit.create(RetrofitEndpoint.class);

    // initialise loading state
    mIsLoading = false;
    mIsLastPage = false;

    // amount of items you want to load per page
    final int pageSize = 20;

    // set up scroll listener
    recyclerView.addOnScrollListener(new  RecyclerView.OnScrollListener() {
            @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            // number of visible items
            int visibleItemCount = layoutManager.getChildCount();
            // number of items in layout
            int totalItemCount = layoutManager.getItemCount();
            // the position of first visible item
            int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();

            boolean isNotLoadingAndNotLastPage = !mIsLoading && !mIsLastPage;
            // flag if number of visible items is at the last
            boolean isAtLastItem = firstVisibleItemPosition + visibleItemCount >= totalItemCount;
            // validate non negative values
            boolean isValidFirstItem = firstVisibleItemPosition >= 0;
            // validate total items are more than possible visible items
            boolean totalIsMoreThanVisible = totalItemCount >= pageSize;
            // flag to know whether to load more
            boolean shouldLoadMore = isValidFirstItem && isAtLastItem && totalIsMoreThanVisible && isNotLoadingAndNotLastPage

            if (shouldLoadMore) loadMoreItems(false);
        }
    });

    // load the first page
    loadMoreItems(true);
}

private void loadMoreItems(boolean isFirstPage) {
    // change loading state
    mIsLoading = true;
    mCurrentPage = mCurrentPage + 1;

    // update recycler adapter with next page
    apiEndpoint.getPagedList(mCurrentPage).enqueue(new Callback<PagedList<Object>>() {
        @Override
        public void onResponse(Call<PagedList<Object>> call, Response<PagedList<Object>> response) {
            PagedList<Object> result = response.body();

            if (result == null) return;
            else if (!isFirstPage) mAdapter.addAll(result.getResults());
            else mAdapter.setList(result.getResults());

            mIsLoading = false;
            mIsLastPage = mCurrentPage == result.getTotalPages();
        }

        @Override
        public void onFailure(Call<PagedList<Object>> call, Throwable t) {
            Log.e("SomeActivity", t.getMessage());
        }
    });
}

回收站适配器:- 对于回收站适配器,您所需要做的就是添加一个将项目添加到其列表的方法,如下所示

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

    private List<Object> list;


    // .. other overridden members

    public void setList(List<Object> list) {
        this.list = list;
        notifyDataSetChanged();
    }

    public void addAll(List<Object> newList) {
        int lastIndex = list.size() - 1;
        list.addAll(newList);
        notifyItemRangeInserted(lastIndex, newList.size());
    }
}

然后,最后一个带页面的 retrofit界面,如下所示:

interface RetrofitEndpoint {

    @GET("paged/list/endpoint")
    Call<PagedList<Object>> getPagedList(@Query("page") int page);
}

希望有帮助。

答案 1 :(得分:2)

@Alimov Shohrukh,我还尝试了多种方法分页

1)Check this link,This is one way

2)我会逐步介绍它

从API端开始-您需要传递pageConunt,pageIndex并根据上述参数获取数据

pageConunt-表示要从服务器获取多少数据,即-10 pageIndex-例如1,2,3等的页码

public class DemoActivity extends BaseActivity{

List<BaseModel> orderList = new ArrayList<>();

    ListAdapter listAdapter;
    LinearLayoutManager layoutManager;
OrderListAdapter orderListAdapter;

    int pageIndex = 1; // you can pass 1,2,3...
    int pageCount = 10; //you can pass 10,20...


    boolean isApiSuccess = false;
    //if api get success == true then you need to work with load more sp we take one boolean variable

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);

        findView();
        setRecyclerViewPagination();

    }

    private void findView() {
         //recyclerview
        rv_po_order_number = findViewById(R.id.rv_po_order_number);

    }


    //custom OnScrollListener
private RecyclerView.OnScrollListener recyclerViewOnScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }

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

            if (isApiSuccess) {
                pageIndex++;
                listTestApiCall(pageIndex, searchQuery);
                Log.e(TAG, pageIndex + " page count ");

                orderListAdapter.showLoading(true);

                rv_po_order_number.post(new Runnable() {
                    public void run() {
                        // There is no need to use notifyDataSetChanged()
                        orderListAdapter.notifyDataSetChanged();
                    }
                });
            }
        }
    };
private void setRecyclerViewPagination() {
        orderList = new ArrayList<>();
        orderListAdapter = new OrderListAdapter(mActivity, orderList);

        layoutManager = new LinearLayoutManager(mActivity, LinearLayoutManager.VERTICAL, false);
        rv_po_order_number.setLayoutManager(layoutManager);
        rv_po_order_number.setHasFixedSize(true);

        rv_po_order_number.setAdapter(orderListAdapter);
        rv_po_order_number.addOnScrollListener(recyclerViewOnScrollListener);

        listTestApiCall(pageCount,pageIndex);

    }

private void listTestApiCall(final int pageCount,final int pageIndex) {

        //  if (CommonUtils.isConnectingToInternet(mActivity)) {
        if (validateInternetConn(mActivity)) {//check internet

            final boolean isFirstPage = pageIndex == 1 ? true : false;

            if (isFirstPage)
                //do your stuff - if you want to show loader

            Call<BaseModel> call = ApiClient.getClient().listApiCall(pageCount, pageIndex);

            call.enqueue(new Callback<BaseModel>() {
                @Override
                public void onResponse(Call<BaseModel> call, Response<BaseModel> response) {
                    try {
                        if (response.isSuccessful()) {

                            boolean success = response.body().getStatus();
                            isApiSuccess = response.body().getStatus();

                            if (success) {

                                List<BaseModel> list = new ArrayList<>();

                                if (response.body().getData() != null) {
                                    list = response.body().getData();

                                    if (isFirstPage)
                                        orderList.clear();

                                    orderList.addAll(response.body().getData());

                                }

                                if (list != null && list.size() > 0) {
                                    isApiSuccess = true;
                                } else {
                                    isApiSuccess = false;
                                }

                            } else if (!success) {
                                isApiSuccess = false;
                                String message = response.body().getMessage();

                            }


                            listAdapter.showLoading(false);
                            listAdapter.notifyDataSetChanged();
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e("Tag", "error=" + e.toString());
                        isApiSuccess = false;
                    }


                }

                @Override
                public void onFailure(Call<BaseModel> call, Throwable t) {
                    Log.e("Tag", "error" + t.toString());

                    isApiSuccess = false;
                                    }
            });
        }
  }
   }

这里是OrderListAdapter

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


   Activity mActivity;

   List<OrderListBaseModel.DataBean> mList;


   PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick;
   DeleteUpdatePOOnClick deleteUpdatePOOnClick;

   public static final int TYPE_FOOTER = 1;
   public static final int TYPE_ITEM = 2;

   protected boolean showLoader = true;

   public OrderListAdapter(Activity mActivity, List<OrderListBaseModel.DataBean> mList, PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick,DeleteUpdatePOOnClick deleteUpdatePOOnClick) {
       this.mActivity = mActivity;
       this.purchaseOrderReceiveOnClick = purchaseOrderReceiveOnClick;
       this.deleteUpdatePOOnClick = deleteUpdatePOOnClick;
       this.mList = mList;


   }

   public OrderListAdapter(Activity mActivity, List<OrderListBaseModel.DataBean> mList) {
       this.mActivity = mActivity;

       this.mList = mList;



   }


   @Override
   public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       if (viewType == TYPE_ITEM) {
           View v = LayoutInflater.from(parent.getContext())
                   .inflate(R.layout.row_purchase_order_receive, parent, false);
           return new DataViewHolder(v, purchaseOrderReceiveOnClick);
       } else if (viewType == TYPE_FOOTER) {
           View v = LayoutInflater.from(parent.getContext())
                   .inflate(R.layout.loading_layout, parent, false);
           return new FooterViewHolder(v);
       } else
           return null;
   }

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


       if (holder instanceof DataViewHolder) {

           final DataViewHolder dataViewHolder = (DataViewHolder) holder;


           final OrderListBaseModel.DataBean dataBean = getItem(position);
           if (dataBean != null) {
               dataViewHolder.setPosition(position);
                dataViewHolder.setSingleBean(dataBean);


           }


       }
   }

   private OrderListBaseModel.DataBean getItem(int position) {
       if (mList.size() > 0)
           return mList.get(position);

       else
           return null;
   }

   public void showLoading(boolean status) {
       showLoader = status;
   }


   @Override
   public int getItemViewType(int position) {
       if ((position == mList.size() - 1) && showLoader) {
           return TYPE_FOOTER;
       }
       return TYPE_ITEM;
   }
   public void removeItem(int position) {
       mList.remove(position);
       notifyItemRemoved(position);
   }
   @Override
   public int getItemCount() {
       return mList.size();
   }


   public static class DataViewHolder extends RecyclerView.ViewHolder {
       int position;
       OrderListBaseModel.DataBean dataBean;
       private TextView tv_row_po_no,textViewOptions;

       public DataViewHolder(View v, final PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick) {
           super(v);
           tv_row_po_no = v.findViewById(R.id.tv_row_po_no);
           textViewOptions = v.findViewById(R.id.textViewOptions);



       }

       public void setPosition(int position) {
           this.position = position;
       }

       public void setSingleBean(OrderListBaseModel.DataBean dataBean) {
           this.dataBean = dataBean;
       }
   }

   private class FooterViewHolder extends RecyclerView.ViewHolder {

       public FooterViewHolder(View view) {
           super(view);

       }
   }


   }

这是xml代码

loading_layout.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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearRoot"
    android:gravity="center_horizontal"
    android:layout_marginTop="@dimen/_5sdp">
<com.app.trackpoint.custom_loader.MYLoader
        android:layout_width="@dimen/_30sdp"
        app:my_color="@color/colorAccent"
        android:layout_height="@dimen/_30sdp" />
</LinearLayout>