base-adapter-helper的RecyclerView版

在這期間也看了簡書作者輕微 的一篇文章:RecyclerView適配器的超省寫法 。發現他的實現原理其實和base-adapter-helper有很大的相似之處,不知道這是英雄所見略同的巧合,還是借鑑了base-adapter-helper,我想還是前者的可能性略大,因爲代碼相似度很低。

好了,回到簡化RecyclerView適配器這個話題上來。

其實總的來說要比ListView實現起來更簡單。思路也和ListView版本很相似。就三點:

  1. 列表數據要使用泛型;

  2. 原本ViewHolder中的View成員變量轉而通過view數組來實現(比如SparseArray);

  3. 把數據綁定通過實現抽象方法來實現。

我更改了一下base-adapter-helper的項目結構:

D7E06BB4-6089-44E1-975D-3CD7D8E91CCC.png


如果你想用RecyclerView的適配器,import recyclerview包下面的QuickAdapter。


首先BaseQuickAdapter

  1. package com.joanzapata.android.recyclerview;
  2.  
  3. import android.content.Context;
  4. import android.support.v7.widget.RecyclerView;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8.  
  9. import java.util.ArrayList;
  10. import java.util.List;
  11.  
  12. /**
  13.  * Created by jianghejie on 15/8/8.
  14.  */
  15. public abstract class BaseQuickAdapter <T, H extends BaseAdapterHelper> extends RecyclerView.Adapter<BaseAdapterHelper> implements View.OnClickListener{
  16.     protected static final String TAG = BaseQuickAdapter.class.getSimpleName();
  17.  
  18.     protected final Context context;
  19.  
  20.     protected final int layoutResId;
  21.  
  22.     protected final List<T> data;
  23.  
  24.     protected boolean displayIndeterminateProgress = false;
  25.  
  26.     private OnItemClickListener mOnItemClickListener = null;
  27.  
  28.     //define interface
  29.     public static interface OnItemClickListener {
  30.         void onItemClick(View view , int position);
  31.     }
  32.  
  33.     /**
  34.      * Create a QuickAdapter.
  35.      * @param context     The context.
  36.      * @param layoutResId The layout resource id of each item.
  37.      */
  38.     public BaseQuickAdapter(Context context, int layoutResId) {
  39.         this(context, layoutResId, null);
  40.     }
  41.  
  42.     /**
  43.      * Same as QuickAdapter#QuickAdapter(Context,int) but with
  44.      * some initialization data.
  45.      * @param context     The context.
  46.      * @param layoutResId The layout resource id of each item.
  47.      * @param data        A new list is created out of this one to avoid mutable list
  48.      */
  49.     public BaseQuickAdapter(Context context, int layoutResId, List<T> data) {
  50.         this.data = data == null ? new ArrayList<T>() : data;
  51.         this.context = context;
  52.         this.layoutResId = layoutResId;
  53.     }
  54.  
  55.     @Override
  56.     public int getItemCount() {
  57.         return data.size();
  58.     }
  59.  
  60.  
  61.     public T getItem(int position) {
  62.         if (position >= data.size()) return null;
  63.         return data.get(position);
  64.     }
  65.     @Override
  66.     public BaseAdapterHelper onCreateViewHolder(ViewGroup viewGroup,  int viewType) {
  67.         View view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutResId, viewGroup, false);
  68.         view.setOnClickListener(this);
  69.         BaseAdapterHelper vh = new BaseAdapterHelper(view);
  70.         return vh;
  71.     }
  72.  
  73.     @Override
  74.     public void onBindViewHolder(BaseAdapterHelper helper,  int position) {
  75.         helper.itemView.setTag(position);
  76.         T item = getItem(position);
  77.         convert((H)helper, item);
  78.     }
  79.  
  80.     /**
  81.      * Implement this method and use the helper to adapt the view to the given item.
  82.      * @param helper A fully initialized helper.
  83.      * @param item   The item that needs to be displayed.
  84.      */
  85.     protected abstract void convert(H helper, T item);
  86.  
  87.     @Override
  88.     public void onClick(View v) {
  89.         if (mOnItemClickListener != null) {
  90.             mOnItemClickListener.onItemClick(v,(int)v.getTag());
  91.         }
  92.     }
  93.  
  94.     public void setOnItemClickListener(OnItemClickListener listener) {
  95.         this.mOnItemClickListener = listener;
  96.     }
  97.  
  98. }

然後是BaseAdapterHelper

在這裏BaseAdapterHelper就是一個RecyclerView.ViewHolder,爲了一致性,我取名爲BaseAdapterHelper。

  1. package com.joanzapata.android.recyclerview;
  2.  
  3. import android.support.v7.widget.RecyclerView;
  4. import android.util.SparseArray;
  5. import android.view.View;
  6. import android.widget.Button;
  7. import android.widget.ImageView;
  8. import android.widget.TextView;
  9.  
  10. /**
  11.  * Created by jianghejie on 15/8/8.
  12.  */
  13. public class BaseAdapterHelper extends RecyclerView.ViewHolder{
  14.     private SparseArray<View> views;
  15.     public BaseAdapterHelper(View itemView){
  16.         super(itemView);
  17.         this.views = new SparseArray<View>();
  18.     }
  19.  
  20.     public TextView getTextView(int viewId) {
  21.         return retrieveView(viewId);
  22.     }
  23.  
  24.     public Button getButton(int viewId) {
  25.         return retrieveView(viewId);
  26.     }
  27.  
  28.     public ImageView getImageView(int viewId) {
  29.         return retrieveView(viewId);
  30.     }
  31.  
  32.     public View getView(int viewId) {
  33.         return retrieveView(viewId);
  34.     }
  35.     
  36.     @SuppressWarnings("unchecked")
  37.     protected <extends View> T retrieveView(int viewId) {
  38.         View view = views.get(viewId);
  39.         if (view == null) {
  40.             view = itemView.findViewById(viewId);
  41.             views.put(viewId, view);
  42.         }
  43.         return (T) view;
  44.     }
  45. }

在前面一片文章中,我們解決base-adapter-helper的缺點是採用拋棄了諸多setXXX方法,直接調用retrieveView,然而感覺那樣會多一行代碼,看起來不夠精煉,在RecyclerView適配器的超省寫法 中我學到了一點,那就是將setXXX改成getXXX,在getXXX方法中做好強制轉換。

而且一般來說,我們只需要很有限的getXXX方法,基本有這三個就可以滿足90%的需求了:

  1.     public TextView getTextView(int viewId) {
  2.         return retrieveView(viewId);
  3.     }
  4.  
  5.     public Button getButton(int viewId) {
  6.         return retrieveView(viewId);
  7.     }
  8.  
  9.     public ImageView getImageView(int viewId) {
  10.         return retrieveView(viewId);
  11.     }

但是有些時候也許我們並不需要知道view的具體類型,比如在設置透明度,可見狀態的時候,所以最好還是增加一個獲得普通view的方法:

  1. public TextView getTextView(int viewId) {
  2.     return retrieveView(viewId);
  3. }
  4.  
  5. public Button getButton(int viewId) {
  6.     return retrieveView(viewId);
  7. }
  8.  
  9. public ImageView getImageView(int viewId) {
  10.     return retrieveView(viewId);
  11. }
  12.  
  13. public View getView(int viewId) {
  14.     return retrieveView(viewId);
  15. }

最後,需要提醒大家一點,就是這種實現方式和傳統的RecyclerView.Adapter在流程上稍微有一點點不同。

傳統RecyclerView的ViewHolder在onCreateViewHolder的時候就已經找到了所有要綁定的view,如下面的ViewHolder

  1. public static class ViewHolder extends RecyclerView.ViewHolder {
  2.     public TextView title;
  3.     public TextView author;
  4.     public TextView description;
  5.     public TextView date;
  6.     public TextView count;
  7.     public ImageView litPic;
  8.  
  9.     public ViewHolder(View view){
  10.         super(view);
  11.         title = (TextView) view
  12.                 .findViewById(R.id.blog_listitem_title);
  13.         author = (TextView) view
  14.                 .findViewById(R.id.blog_listitem_author);
  15.         date = (TextView) view
  16.                 .findViewById(R.id.blog_listitem_date);
  17.         litPic = (ImageView) view
  18.                 .findViewById(R.id.blog_listitem_litpic);
  19.         description = (TextView) view
  20.                 .findViewById(R.id.description);
  21.     }
  22. }

這些View都是成員變量,在調用構造函數的時候已經初始化了。

而我們的實現中,這些View是在綁定的時候被初始化的,我們必須這樣做,因爲我們無法預知綁定的item的佈局以及數據模型是怎樣的。

不過這並不會帶來絲毫的性能損失,我們做的只是把findViewById放在了onBindViewHolder中,並且只有第一次綁定的時候纔會去執行findViewById。

使用

  1. mRecyclerView = (RecyclerView) mPageView.findViewById(R.id.my_recycler_view);
  2. mRecyclerView.enableLoadmore();
  3.  
  4. LinearLayoutManager layoutManager = new LinearLayoutManager(appContext);
  5. layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
  6. layoutManager.scrollToPosition(0);
  7. mRecyclerView.setLayoutManager(layoutManager);
  8.  
  9. //init the  listview
  10. mAdapter = new QuickAdapter<Blog>(appContext, R.layout.item_blog_list, blogData){
  11.    @Override
  12.    protected void convert(BaseAdapterHelper helper, Blog blog) {
  13.       helper.getTextView(R.id.blog_listitem_title).setText(Html.fromHtml(blog.getTitle()));
  14.       helper.getTextView(R.id.blog_listitem_author).setText(blog.getAuthor());
  15.       helper.getTextView(R.id.description).setText(blog.getDescription());
  16.       Picasso.with(context).load(blog.getImageUrl()).into(helper.getImageView(R.id.blog_listitem_litpic));
  17.       }
  18.    }
  19. };
  20. mRecyclerView.setAdapter(mAdapter);

是不是和ListView版本非常一致。

源碼下載

現在只提供網盤的下載地址,完善之後再提交到github。

http://pan.baidu.com/s/1kT9wBHH 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章