在這期間也看了簡書作者輕微 的一篇文章:RecyclerView適配器的超省寫法 。發現他的實現原理其實和base-adapter-helper有很大的相似之處,不知道這是英雄所見略同的巧合,還是借鑑了base-adapter-helper,我想還是前者的可能性略大,因爲代碼相似度很低。
好了,回到簡化RecyclerView適配器這個話題上來。
其實總的來說要比ListView實現起來更簡單。思路也和ListView版本很相似。就三點:
-
列表數據要使用泛型;
-
原本ViewHolder中的View成員變量轉而通過view數組來實現(比如SparseArray);
-
把數據綁定通過實現抽象方法來實現。
我更改了一下base-adapter-helper的項目結構:
如果你想用RecyclerView的適配器,import recyclerview包下面的QuickAdapter。
首先BaseQuickAdapter
- package com.joanzapata.android.recyclerview;
- import android.content.Context;
- import android.support.v7.widget.RecyclerView;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Created by jianghejie on 15/8/8.
- */
- public abstract class BaseQuickAdapter <T, H extends BaseAdapterHelper> extends RecyclerView.Adapter<BaseAdapterHelper> implements View.OnClickListener{
- protected static final String TAG = BaseQuickAdapter.class.getSimpleName();
- protected final Context context;
- protected final int layoutResId;
- protected final List<T> data;
- protected boolean displayIndeterminateProgress = false;
- private OnItemClickListener mOnItemClickListener = null;
- //define interface
- public static interface OnItemClickListener {
- void onItemClick(View view , int position);
- }
- /**
- * Create a QuickAdapter.
- * @param context The context.
- * @param layoutResId The layout resource id of each item.
- */
- public BaseQuickAdapter(Context context, int layoutResId) {
- this(context, layoutResId, null);
- }
- /**
- * Same as QuickAdapter#QuickAdapter(Context,int) but with
- * some initialization data.
- * @param context The context.
- * @param layoutResId The layout resource id of each item.
- * @param data A new list is created out of this one to avoid mutable list
- */
- public BaseQuickAdapter(Context context, int layoutResId, List<T> data) {
- this.data = data == null ? new ArrayList<T>() : data;
- this.context = context;
- this.layoutResId = layoutResId;
- }
- @Override
- public int getItemCount() {
- return data.size();
- }
- public T getItem(int position) {
- if (position >= data.size()) return null;
- return data.get(position);
- }
- @Override
- public BaseAdapterHelper onCreateViewHolder(ViewGroup viewGroup, int viewType) {
- View view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutResId, viewGroup, false);
- view.setOnClickListener(this);
- BaseAdapterHelper vh = new BaseAdapterHelper(view);
- return vh;
- }
- @Override
- public void onBindViewHolder(BaseAdapterHelper helper, int position) {
- helper.itemView.setTag(position);
- T item = getItem(position);
- convert((H)helper, item);
- }
- /**
- * Implement this method and use the helper to adapt the view to the given item.
- * @param helper A fully initialized helper.
- * @param item The item that needs to be displayed.
- */
- protected abstract void convert(H helper, T item);
- @Override
- public void onClick(View v) {
- if (mOnItemClickListener != null) {
- mOnItemClickListener.onItemClick(v,(int)v.getTag());
- }
- }
- public void setOnItemClickListener(OnItemClickListener listener) {
- this.mOnItemClickListener = listener;
- }
- }
然後是BaseAdapterHelper
在這裏BaseAdapterHelper就是一個RecyclerView.ViewHolder,爲了一致性,我取名爲BaseAdapterHelper。
- package com.joanzapata.android.recyclerview;
- import android.support.v7.widget.RecyclerView;
- import android.util.SparseArray;
- import android.view.View;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.widget.TextView;
- /**
- * Created by jianghejie on 15/8/8.
- */
- public class BaseAdapterHelper extends RecyclerView.ViewHolder{
- private SparseArray<View> views;
- public BaseAdapterHelper(View itemView){
- super(itemView);
- this.views = new SparseArray<View>();
- }
- public TextView getTextView(int viewId) {
- return retrieveView(viewId);
- }
- public Button getButton(int viewId) {
- return retrieveView(viewId);
- }
- public ImageView getImageView(int viewId) {
- return retrieveView(viewId);
- }
- public View getView(int viewId) {
- return retrieveView(viewId);
- }
- @SuppressWarnings("unchecked")
- protected <T extends View> T retrieveView(int viewId) {
- View view = views.get(viewId);
- if (view == null) {
- view = itemView.findViewById(viewId);
- views.put(viewId, view);
- }
- return (T) view;
- }
- }
在前面一片文章中,我們解決base-adapter-helper的缺點是採用拋棄了諸多setXXX方法,直接調用retrieveView,然而感覺那樣會多一行代碼,看起來不夠精煉,在RecyclerView適配器的超省寫法 中我學到了一點,那就是將setXXX改成getXXX,在getXXX方法中做好強制轉換。
而且一般來說,我們只需要很有限的getXXX方法,基本有這三個就可以滿足90%的需求了:
- public TextView getTextView(int viewId) {
- return retrieveView(viewId);
- }
- public Button getButton(int viewId) {
- return retrieveView(viewId);
- }
- public ImageView getImageView(int viewId) {
- return retrieveView(viewId);
- }
但是有些時候也許我們並不需要知道view的具體類型,比如在設置透明度,可見狀態的時候,所以最好還是增加一個獲得普通view的方法:
- public TextView getTextView(int viewId) {
- return retrieveView(viewId);
- }
- public Button getButton(int viewId) {
- return retrieveView(viewId);
- }
- public ImageView getImageView(int viewId) {
- return retrieveView(viewId);
- }
- public View getView(int viewId) {
- return retrieveView(viewId);
- }
最後,需要提醒大家一點,就是這種實現方式和傳統的RecyclerView.Adapter在流程上稍微有一點點不同。
傳統RecyclerView的ViewHolder在onCreateViewHolder的時候就已經找到了所有要綁定的view,如下面的ViewHolder
- public static class ViewHolder extends RecyclerView.ViewHolder {
- public TextView title;
- public TextView author;
- public TextView description;
- public TextView date;
- public TextView count;
- public ImageView litPic;
- public ViewHolder(View view){
- super(view);
- title = (TextView) view
- .findViewById(R.id.blog_listitem_title);
- author = (TextView) view
- .findViewById(R.id.blog_listitem_author);
- date = (TextView) view
- .findViewById(R.id.blog_listitem_date);
- litPic = (ImageView) view
- .findViewById(R.id.blog_listitem_litpic);
- description = (TextView) view
- .findViewById(R.id.description);
- }
- }
這些View都是成員變量,在調用構造函數的時候已經初始化了。
而我們的實現中,這些View是在綁定的時候被初始化的,我們必須這樣做,因爲我們無法預知綁定的item的佈局以及數據模型是怎樣的。
不過這並不會帶來絲毫的性能損失,我們做的只是把findViewById放在了onBindViewHolder中,並且只有第一次綁定的時候纔會去執行findViewById。
使用
- mRecyclerView = (RecyclerView) mPageView.findViewById(R.id.my_recycler_view);
- mRecyclerView.enableLoadmore();
- LinearLayoutManager layoutManager = new LinearLayoutManager(appContext);
- layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
- layoutManager.scrollToPosition(0);
- mRecyclerView.setLayoutManager(layoutManager);
- //init the listview
- mAdapter = new QuickAdapter<Blog>(appContext, R.layout.item_blog_list, blogData){
- @Override
- protected void convert(BaseAdapterHelper helper, Blog blog) {
- helper.getTextView(R.id.blog_listitem_title).setText(Html.fromHtml(blog.getTitle()));
- helper.getTextView(R.id.blog_listitem_author).setText(blog.getAuthor());
- helper.getTextView(R.id.description).setText(blog.getDescription());
- Picasso.with(context).load(blog.getImageUrl()).into(helper.getImageView(R.id.blog_listitem_litpic));
- }
- }
- };
- mRecyclerView.setAdapter(mAdapter);
是不是和ListView版本非常一致。
源碼下載
現在只提供網盤的下載地址,完善之後再提交到github。