Retrofit+SwipeRefreshlayout+RecyclerView to implement pull-up refresh and paging load

Posted by jakeklem on Fri, 03 Apr 2020 03:29:53 +0200

Preface:

In the process of project development, we usually have the demand of "paging load". Paging load is to display data in the form of list. On the premise of having a network, we can manually obtain more data through pull-down refresh. When there is no more data, we will be reminded that we do not have more data.        

Knowledge points used:

  1. Retrofit to implement network request
  2. Recyclerview display list information
  3. Swiperefreshlayout implements pull-down refresh and pull-up loading more
  4. Picasso load picture

Implementation code

1. Configure gradle dependency

//retrofit
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
//recyclerview
compile 'com.android.support:recyclerview-v7:25.0.1'
//picasso
compile 'com.squareup.picasso:picasso:2.3.2'

2. Add SwipyRefreshLayout to layout file

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:my="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFECECEB"
    android:orientation="vertical">

    <uk.co.common.ui.pull.SwipyRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        my:direction="both">

        <!--Solve RecyclerView And TextView Control conflict-->
        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/rv_offer_personal_loans"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="10dp"
                    android:layout_marginTop="10dp"
                    android:divider="#FFFFFFFD" />

                <TextView
                    android:id="@+id/tv_bottom_text"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="10dp"
                    android:layout_marginTop="10dp"
                    android:text="I am bottom text."
                    android:textColor="#384f6f"
                    android:textSize="14sp"
                    android:visibility="gone" />
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    </uk.co.common.ui.pull.SwipyRefreshLayout>

</LinearLayout>

3. Adapter code

​
public class OfferLoansRVAdapter extends RecyclerView.Adapter<OfferLoansRVAdapter.ViewHolder> implements View.OnClickListener {
    public List<Offer_personal_loans.LoansBean> LoansBeens;
    public Context context;

    public OfferLoansRVAdapter(Context context, List<Offer_personal_loans.LoansBean> loansBeans) {
        super();
        this.context = context;
        this.LoansBeens = loansBeans;
    }

    //Declare the OnRecyclerViewListener object
    private OfferLoansRVAdapter.OnRecyclerViewListener mOnRecyclerViewListener = null;

    @Override
    public void onClick(View v) {
        if (mOnRecyclerViewListener != null) {
            mOnRecyclerViewListener.onItemClick(v, (int) v.getTag());
        }
    }

    //Define the onrecyclerviewlistener interface
    public interface OnRecyclerViewListener {
        void onItemClick(View view, int position);
    }

    //Set the method the listener uses to pass data to the interface object defined above
    public void setOnItemClickListener(OfferLoansRVAdapter.OnRecyclerViewListener listener) {
        this.mOnRecyclerViewListener = listener;
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //R. Layout.common'loan'item: the layout file of the item
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.common_loan_item, parent, false);
        OfferLoansRVAdapter.ViewHolder vh = new OfferLoansRVAdapter.ViewHolder(view);
        view.setOnClickListener(this);
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        RecyclerView.ViewHolder viewHolder = holder;
        try {
            String logo_url = LoansBeens.get(position).getLogo_url();
            Picasso.with(Global.mContext).load(logo_url).into(holder.imgLoanLogo);
            ...

            holder.imgLoanCheck.setVisibility(View.VISIBLE);
            //Save the position in the tag of the itemView to implement the click event
            holder.itemView.setTag(position);
        } catch (Exception e) {
        }

    }

    /*
     *This is an important method to add List data when paging data
     */
    public void addItem(List<Offer_personal_loans.LoansBean> loansBeans) {
        try {
            for (Offer_personal_loans.LoansBean loansBean : loansBeans)
                LoansBeens.add(loansBean);
        } catch (ConcurrentModificationException e) {
            e.printStackTrace();
        }

    }

    @Override
    public int getItemCount() {
        return LoansBeens == null ? 0 : LoansBeens.size();
    }

    public Offer_personal_loans.LoansBean getItem(int position) {
        return LoansBeens.get(position);
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imgLoanLogo;
        ...

        public ViewHolder(View view) {
            super(view);
            imgLoanLogo = (ImageView) view.findViewById(R.id.img_loan_logo);
            ...
        }
    }
}



​

4. Code implemented in Fragment

public class OfferPersonalLoansFragment extends BaseFragment implements SwipyRefreshLayout.OnRefreshListener {
    private SwipyRefreshLayout refreshLayout;
    private RecyclerView rvOfferPersonalLoans;
    private Offer_personal_loans offerPersonalLoans;
    private List<Offer_personal_loans.LoansBean> personalLoansBeen;
    private List<List<Offer_personal_loans.LoansBean>> offerPersonalLoansList;
    private OfferLoansRVAdapter offerPersonalLoansRVAdapter;
    private TextView tvBottomText;
    //Presenter
    private CommonPresenter commonPresenter;
    //Offset
    private int offset = 0;
    //Restriction number
    private int limit = 5;

    @Override
    public int getLayoutRes() {
        return R.layout.offer_personal_loans;
    }

    @Override
    public void initView() {
        refreshLayout = (SwipyRefreshLayout) findView(R.id.refreshLayout);
        refreshLayout.setOnRefreshListener(this);
        rvOfferPersonalLoans = (RecyclerView) findView(R.id.rv_offer_personal_loans);
        rvOfferPersonalLoans.setLayoutManager(new LinearLayoutManager(getActivity()));
        tvBottomText = (TextView) findView(R.id.tv_bottom_text);
        }

    @Override
    public void initListener() {

    }

    @Override
    public void initData() {
            //Network request data
            showProgressDialog("", "Please wait...");
            commonPresenter = new CommonPresenter(this);
            commonPresenter.getOfferPersonalLoans(uuid, offset * limit, limit);
        }
    }

    @Override
    public void onClick(View v, int id) {

    }

     /*
      *Method of invocation after network request is successful
      */
    @Override
    public void onHttpSuccess(int reqType, Message msg) {
        if (reqType == IHttpService.HTTP_GET_OFFER_PERSONAL_LOANS) {
            hideProgressDialog();
            offerPersonalLoans = (Offer_personal_loans) msg.obj;
            try {
                personalLoansBeen = offerPersonalLoans.getLoans();
                offerPersonalLoansList = new ArrayList<>();
                offerPersonalLoansList.add(personalLoansBeen);
            } catch (Exception e) {
                e.printStackTrace();
            }
            initLoanRecyclerView();
            tvBottomText.setVisibility(View.VISIBLE);
        }
    }

    private void initLoanRecyclerView() {
        if (offerPersonalLoansRVAdapter == null) {//Sentence blank
            offerPersonalLoansRVAdapter = new OfferLoansRVAdapter(getActivity(), personalLoansBeen);
            rvOfferPersonalLoans.setAdapter(offerPersonalLoansRVAdapter);
        } else {
            //Before loading data, when manually refreshing / paging loading data, this is to add List data
            offerPersonalLoansRVAdapter.addItem(personalLoansBeen);
            offerPersonalLoansRVAdapter.notifyDataSetChanged();
        }

        refreshLayout.setRefreshing(false);//Remember to add this sentence

        //Unified handling of click events
        offerPersonalLoansRVAdapter.setOnItemClickListener(new  OfferLoansRVAdapter.OnRecyclerViewListener() {
            @Override
            public void onItemClick(View view, int position) {
              ...
            }
        });
    }

    /*
     *Pull up refresh, request interface
     */
    @Override
    public void onRefresh(int index) {
            commonPresenter = new CommonPresenter(this);
            commonPresenter.getOfferPersonalLoans(uuid, offset * limit, limit);
    }
    
    /*
     *Paging load, request interface
     */
    @Override
    public void onLoad(int index) {
        String uuid = SharedPreUtil.getString(Global.mContext, "membership_uuid", "");
        if (!TextUtils.isEmpty(uuid)) {
            commonPresenter = new CommonPresenter(this);
            offset++;//Offset + 1 per interface request (designed according to interface)
            commonPresenter.getOfferPersonalLoans(uuid, offset * limit, limit);
        }

    }

     /*
      *Method of calling after failure of network request
      */
    @Override
    public void onHttpError(int reqType, ArrayList<String> error) {
        if (reqType == IHttpService.HTTP_GET_OFFER_PERSONAL_LOANS) {
            hideProgressDialog();
        }
    }

    /*
      *Method called by network timeout
      */
    @Override
    public void onHttpFailure(int reqType, String error) {
        if (reqType == IHttpService.HTTP_GET_OFFER_PERSONAL_LOANS) {
            hideProgressDialog();
        }
    }
    
    /*
     *Method called by server error
     */
    @Override
    public void onServerError(int reqType) {
        if (reqType == IHttpService.HTTP_GET_OFFER_PERSONAL_LOANS) {
            hideProgressDialog();
        }
    }

}

5. Operation rendering:

      

6. Summary: page by page loading is to load data page by page. When there is no more data to load when sliding to the bottom, we can manually call the interface and refresh RecyclerView. The pull-up function cannot be used. Only after the pull-down refresh, the data can be loaded again. In this way, not only the burden of the server can be reduced, but also the user can save traffic, so as to improve the user experience.

Topics: Android network Retrofit Gradle