preface

Since RecyclerVIew came out after trying to use it, the effect is really much better than ListView. But we found a problem, because the Adapter of RecyclerView must inherit from recyclerView. Adapter and specify the ViewHolder we wrote to be generic. In order to achieve universal effect, we directly refer to the Java Bean properties that need to be passed in with a generic T. ListView (ListView, ListView, ListView, ListView, ListView, ListView, ListView, ListView)

  • getItemViewType(int position)
  • getItemCount()
  • onCreateViewHolder(ViewGroup parent, int viewType)
  • onBindViewHolder(RecyclerView.ViewHolder holder, int position)
  • And an interface to define a click event, OnItemClickListener

Then there is the question of what to do to load more in order to give the user a friendly hint. Here take you to package RecyclerView.Adapter, first look at the effect picture:

Method of use

Take a look at the wrapped BaseRecyclerViewAdapter code

BaseRecyclerViewAdapter

public abstract class BaseRecyclerViewAdapter<T>
        extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

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

    private int mItemLayoutRes = -1;
    protected Context mContext;
    protected List<T> mList = new ArrayList<>();
    protected OnItemClickListener<T> mOnItemClickListener;
    protected OnReloadClickListener mOnReloadClickListener;

    private FooterViewHolder mFooterViewHolder;

    public BaseRecyclerViewAdapter(Context context, @LayoutRes int itemLayoutRes) {
        this.mContext = context;
        this.mItemLayoutRes = itemLayoutRes;
    }

    public void setOnItemClickListener(OnItemClickListener<T> onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

    public void setOnReloadClickListener(OnReloadClickListener onReloadClickListener) {
        this.mOnReloadClickListener = onReloadClickListener;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_FOOTER) {
            View view = getView(parent, R.layout.rv_item_footer);
            return mFooterViewHolder = new FooterViewHolder(view);
        } else {
            View view = getView(parent, mItemLayoutRes);
            final BaseViewHolder baseViewHolder = new BaseViewHolder(view);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if(mOnItemClickListener ! =null) {
                        int position = baseViewHolder.getLayoutPosition();
                        mOnItemClickListener.onItemClick(view, mList.get(position)); }}});return baseViewHolder;
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof BaseViewHolder && mList.size() ! =0&& mList.size() ! = position) { BaseViewHolder viewHolder = (BaseViewHolder) holder; onBindViewHolder(viewHolder, mList.get(position), position);
        } else {
            ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
            if(layoutParams ! =null && layoutParams instanceof
                    StaggeredGridLayoutManager.LayoutParams) {
                StaggeredGridLayoutManager.LayoutParams params =
                        (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
                params.setFullSpan(true); }}}/** * item ** @param holder ViewHolder * @param data entity data * @param position index */
    protected abstract void onBindViewHolder(BaseViewHolder holder, T data, int position);

    protected View getView(ViewGroup parent, int layoutId) {
        return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
    }

    @Override
    public int getItemCount() {
        int itemCount = mList.size();
        return itemCount == 0 ? 0 : itemCount + 1;
    }

    @Override
    public int getItemViewType(int position) {
        if (position + 1 == getItemCount() && mList.size() > 0) {
            return TYPE_FOOTER;
        }
        return TYPE_ITEM;
    }

    public void setData(List<T> data) {
        mList.clear();
        mList.addAll(data);
        notifyDataSetChanged();
    }

    public void addMoreData(List<T> data) {
        mList.addAll(data);
        notifyDataSetChanged();
    }

    public void deleteData(int position) {
        mList.remove(position);
        notifyItemRemoved(position);
    }

    private class FooterViewHolder extends RecyclerView.ViewHolder {

        ProgressBar progressBar;
        TextView prompt;

        public FooterViewHolder(View itemView) { super(itemView); progressBar = itemView.findViewById(R.id.pb_loading); prompt = itemView.findViewById(R.id.tv_prompt); }}public void setLoading() {
        mFooterViewHolder.prompt.setText("Loading more");
        mFooterViewHolder.prompt.setVisibility(View.VISIBLE);
        mFooterViewHolder.progressBar.setVisibility(View.VISIBLE);
    }

    public void setNotMore() {
        mFooterViewHolder.prompt.setText("There is no more.");
        mFooterViewHolder.progressBar.setVisibility(View.GONE);
    }

    public void setNetError() {
        mFooterViewHolder.prompt.setText("Load failed, click retry");
        mFooterViewHolder.prompt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mOnReloadClickListener ! =null) { mOnReloadClickListener.onClick(); }}}); mFooterViewHolder.progressBar.setVisibility(View.GONE); }}Copy the code

Create MainAdapter

public class MainAdapter extends BaseRecyclerViewAdapter<String> {

    public MainAdapter(Context context) {
        super(context, R.layout.rv_item_main);
}

    @Override
    protected void onBindViewHolder(BaseViewHolder holder, String data, intposition) { holder.setTextView(R.id.item_text_view,data); }}Copy the code

To implement the MainAdapter constructor, you must call super(context, r.layout.rv_item_main), To initialize a constructor in the parent class BaseRecyclerViewAdapter

public BaseRecyclerViewAdapter(Context context, @LayoutRes int  itemLayoutRes) {
        this.mContext = context;
        this.mItemLayoutRes = itemLayoutRes;
    }Copy the code

GetItemLayoutRes () = getItemLayoutRes() = getItemLayoutRes();

Used in an Activity

public class MainActivity extends AppCompatActivity {

    private static final int COUNT = 15;

    private MainAdapter mAdapter;
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mRecyclerView;

    private int page = 1;
    private boolean isRefresh;
    private boolean isLoadMore;

    private boolean isFailed = false;

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

        initView();
        initSwipeRefreshLayout();
        initRecyclerView();
        requestData(COUNT, page);
    }

    private void initView() {
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    }

    private void initSwipeRefreshLayout() {
        mSwipeRefreshLayout.setRefreshing(true);
        mSwipeRefreshLayout.setColorSchemeColors(getResources()
                .getIntArray(R.array.swipeRefreshLayoutColor));
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                page = 1;
                isRefresh = true; requestData(COUNT, page); }}); }private void initRecyclerView() {
        mAdapter = new MainAdapter(this);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(mAdapter);
        // Click events
        mAdapter.setOnItemClickListener(new OnItemClickListener<String>() {
            @Override
            public void onItemClick(View view, String data) {
                Toast.makeText(MainActivity.this."Clicked"+ data, Toast.LENGTH_SHORT).show(); }});// Request exception retry listening
        mAdapter.setOnReloadClickListener(new OnReloadClickListener() {
            @Override
            public void onClick() { mAdapter.setLoading(); requestData(COUNT, page); }});// Slide to the bottom to listen for events
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
                int totalItemCount = recyclerView.getAdapter().getItemCount();
                int lastVisibleItemPosition = lm.findLastVisibleItemPosition();
                int visibleItemCount = recyclerView.getChildCount();
                if(! isRefresh && ! isLoadMore && newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItemPosition == totalItemCount -1 && visibleItemCount > 0) {
                    isLoadMore = true;
                    isRefresh = false; mAdapter.setLoading(); requestData(COUNT, page); }}}); }/** * Simulates network request data ** @paramCount Number of requests * @paramPage Request page number */
    private void requestData(int count, final int page) {
        final List<String> list = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            list.add("item " + i);
        }
        // Delay execution
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                // Simulate a request failure
                if (isFailed && page == 3) {
                    onFailed("No Network link");
                    isFailed = false;
                    return;
                }else if (page == 4){
                    list.clear();
                }
                isFailed = true; resultData(list); }},1500);
    }

    /** * The data returned after the successful request for data ** @paramList Data source */
    private void resultData(List<String> list) {
        closeRefreshing();
        if (isRefresh) {
            if(list ! =null && list.size() > 0) {
                mAdapter.setData(list);
                page++;
            } else {
                Toast.makeText(this."No data at present", Toast.LENGTH_SHORT).show(); }}else {
            if(list ! =null && list.size() > 0) {
                Log.d("wz"."Load more");
                mAdapter.addMoreData(list);
                page++;
            } else {
                mAdapter.setNotMore();
            }
        }
        isRefresh = false;
        isLoadMore = false;
    }

    /** * Result of simulated data request failure ** @param errorMsg msg
     */
    public void onFailed(String errorMsg) {
        closeRefreshing();
        if (mAdapter.getItemCount() == 0) {
            Toast.makeText(this."Loading error:" + errorMsg, Toast.LENGTH_SHORT).show();
        } else{ mAdapter.setNetError(); }}/** * Close SwipeRefreshLayout under drag */
    private void closeRefreshing() {
        if (mSwipeRefreshLayout.isRefreshing()) {
            mSwipeRefreshLayout.setRefreshing(false); }}}Copy the code

Here I am a simulation test, real use is not that complicated, just do what you want to do.

BaseViewHolder

RecyclerView requires ViewHolder mode to be used. Generally, we need to create a new ViewHolder and pass it into Adapter as a generic. So to create a generic Adapter, you must have a generic ViewHolder.

First of all, let’s determine the main function of the ViewHolder. In fact, the ViewHolder is to store the corresponding convertView word View to be operated by the member variable, so as to avoid findViewById every time and thus improve the efficiency of operation.

There is no way to determine which member views to create for different itemTypes. Instead, we have to store them as collections. The code is as follows:

public class BaseViewHolder extends RecyclerView.ViewHolder {

    private SparseArray<View> mViews;
    private View mConvertView;

    public BaseViewHolder(View itemView) {
        super(itemView);
        mConvertView = itemView;
        mViews = new SparseArray<View>();
    }

    public static BaseViewHolder get(ViewGroup parent, int layoutId) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
        return get(itemView);
    }

    public static BaseViewHolder get(View view){
        return new BaseViewHolder(view);
    }

    /** * Get control ** from viewId @param viewId
     * @return* /
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

    public BaseViewHolder setTextView(int viewId, String text) {
        TextView view = getView(viewId);
        view.setText(text);
        return this; }}Copy the code

The code is very simple, our ViewHolder inherits recyclerView. ViewHolder, internal by SparseArray cache our itemView child View, so as to get a general ViewHolder. Every time we want to create a ViewHolder we just pass in our view.

ItemView Click event

public interface OnItemClickListener<T> {

    /** * click event *@param view itemView
     * @paramData Data of the entity class */
    void onItemClick(View view, T data);

}Copy the code

Here we define a generic interface that corresponds to the generic T class in the BaseRecyclerViewAdapter.

Bottom retry click events

public interface OnReloadClickListener {

    /** * Retry the click event */
    void onClick();
}Copy the code

OnClick () is triggered by clicking on item only if the bottom load fails

At the end

See more articles