【问题标题】:How to handle pagination/load more in Retrofit 2.0?如何在 Retrofit 2.0 中处理分页/加载更多?
【发布时间】:2018-08-13 12:12:54
【问题描述】:

我还没有找到合适的例子来说明如何让应用程序在向下滚动 RecyclerView 时从 Retrofit onResponse 加载更多项目。

这是我如何加载我的拳头 20 件物品:

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

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

我的回收站视图

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 中正确使用分页吗?你在 Retrofit 中使用了哪些库,或者向我展示了你是如何做到的?提前谢谢你

【问题讨论】:

  • 使用google的paging支持库

标签: android pagination gson retrofit


【解决方案1】:

你需要三件事来实现这一点,你需要:

  1. 您需要一个用于回收站视图的滚动监听器。
  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());
    }
}

最后是你的 改造界面 获取页面,如下所示:

interface RetrofitEndpoint {

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

希望对您有所帮助。

【讨论】:

    【解决方案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>
    

    【讨论】:

      猜你喜欢
      • 2016-11-13
      • 2018-07-15
      • 1970-01-01
      • 2016-08-29
      • 1970-01-01
      • 2016-11-07
      • 2017-09-26
      • 2021-04-20
      • 2016-07-02
      相关资源
      最近更新 更多