recyclerView程序员Android开发经验谈

使用RecyclerView避免创建很多Adapter,使用注解

2018-01-16  本文已影响65人  C盘无限大

正常使用RecyclerView使用到类有:数据类bean、数据绑定ViewHolder、布局绑定Adapter。

因为数据类型不同或者布局不同导致显示新列表时都要定义一次bean、ViewHolder和Adapter,在这里试试通过注解绑定ViewHolder,去除重复定义Adapter这步。

定义绑定ViewHolder注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HolderClass {
    Class<?> value();
}

绑定布局注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HolderLayoutRes {
    int value();
}

在定义ViewHolder基类,实现一些常用View方法:


public class CommonHolder<T> extends RecyclerView.ViewHolder{

    @IntDef({View.VISIBLE, View.INVISIBLE, View.GONE})
    @Retention(RetentionPolicy.SOURCE)
    private @interface Visibility {}

    private SparseArray<View> mViews;

    protected T mData;

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

    protected void bindData(T data){
        this.mData = data;
    }

    public CommonHolder setVisibility(@IdRes int id, @Visibility int visible){
        getView(id).setVisibility(visible);
        return this;
    }

    public CommonHolder setBackgroundColor(@IdRes int id, @ColorInt int color) {
        getView(id).setBackgroundColor(color);
        return this;
    }

    public CommonHolder setBackgroundResource(@IdRes int id, @ColorRes int color) {
        getView(id).setBackgroundResource(color);
        return this;
    }

    /*#########################  TextView  #########################*/
    public CommonHolder setText(@IdRes int id, @StringRes int strRes) {
        ((TextView) getView(id)).setText(strRes);
        return this;
    }

    public CommonHolder setText(@IdRes int id, String strRes) {
        ((TextView) getView(id)).setText(strRes);
        return this;
    }

    public CommonHolder setTextColor(@IdRes int id, @ColorInt int color) {
        ((TextView) getView(id)).setTextColor(color);
        return this;
    }

    public CommonHolder setTextSize(@IdRes int id, @DimenRes int size){
        ((TextView) getView(id)).setTextSize(TypedValue.COMPLEX_UNIT_PX, itemView.getResources().getDimensionPixelSize(size));
        return this;
    }

    public CommonHolder setTextSize(@IdRes int id, float size){
        ((TextView) getView(id)).setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
        return this;
    }

    public CommonHolder setTextface(@IdRes int id, Typeface typeface){
        ((TextView) getView(id)).setTypeface(typeface);
        return this;
    }

    /*#########################  ImageView  #########################*/
    public CommonHolder setImageDrawable(@IdRes int id, Drawable drawable){
        ((ImageView) getView(id)).setImageDrawable(drawable);
        return this;
    }

    public CommonHolder setImageResource(@IdRes int id, @DrawableRes int drawable){
        ((ImageView) getView(id)).setImageResource(drawable);
        return this;
    }

    public CommonHolder setImageBitmap(@IdRes int id, Bitmap bitmap){
        ((ImageView) getView(id)).setImageBitmap(bitmap);
        return this;
    }

    public CommonHolder setImageBitmap(@IdRes int id, ImageView.ScaleType type){
        ((ImageView) getView(id)).setScaleType(type);
        return this;
    }

    /*#########################  CheckBox  #########################*/
    public CommonHolder setCheck(@IdRes int id, boolean check){
        ((CheckBox) getView(id)).setChecked(check);
        return this;
    }

    public CommonHolder toggle(@IdRes int id){
        ((CheckBox) getView(id)).toggle();
        return this;
    }

    public <T extends View> T getView(@IdRes int id){
        T view = (T) mViews.get(id);
        if (view == null) {
            view = (T) itemView.findViewById(id);
            mViews.put(id, view);
        }
        return view;
    }

}

重新定义Adapter的最大原因是因为每个布局使用的ViewHolder不一样,所以这里使用构造器创建每个布局的ViewHolder:


public class TestAdapter<T, H extends CommonHolder<T>> extends RecyclerView.Adapter<H>{
    private static List<LayoutBeanHolder> layoutBeanHolders = new ArrayList<>();

    protected List<T> mListData;

    public TestAdapter(List<T> mListData) {
        this.mListData = mListData;
    }

    public TestAdapter() {
        this.mListData = new ArrayList<>();
    }

    @Override
    public H onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
        Class holder = indexHolder(viewType);
        H commonHolder = null;
        if (holder != null) {
            try {
                //这里用构造器创建实例
                Constructor constructor = holder.getConstructor(View.class);
                commonHolder =  (H) constructor.newInstance(view);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        if (commonHolder == null) {
            commonHolder = (H) new CommonHolder<>(view);
        }
        return commonHolder;
    }

    @Override
    public void onBindViewHolder(H holder, int position) {
        holder.bindData(mListData.get(position));
    }

    /**
     * 获取bean中的布局,以布局id为ViewType
     */
    @Override
    public int getItemViewType(int position) {
        Class<?> clazz = mListData.get(position).getClass();
        int layout = indexLayoutRes(clazz);
        if (layout != -1) {
            return layout;
        }
        HolderLayoutRes annotation = clazz.getAnnotation(HolderLayoutRes.class);
        if (annotation != null) {
            layout = annotation.value();
            HolderClass viewHolderClass = clazz.getAnnotation(HolderClass.class);
            if (viewHolderClass != null) {
                layoutBeanHolders.add(new LayoutBeanHolder(clazz, viewHolderClass.value(), layout));
            } else {
                layoutBeanHolders.add(new LayoutBeanHolder(clazz, layout));
            }
            return layout;
        } else {
            throw new IllegalArgumentException("class : " + clazz +" no ViewHolderLayoutRes");
        }
    }

    /**
     * 根据布局id获取绑定的ViewHolder
     */
    private Class<?> indexHolder(int layoutRes){
        for (LayoutBeanHolder holder : layoutBeanHolders) {
            if (layoutRes == holder.layoutRes) {
                return holder.holderClass;
            }
        }
        return null;
    }


    /**
     * 根据item类型获取布局id
     */
    private int indexLayoutRes(Class<?> beanClass){
        for (LayoutBeanHolder holder : layoutBeanHolders) {
            if (beanClass.equals(holder.beanClass)) {
                return holder.layoutRes;
            }
        }
        return -1;
    }

    @Override
    public int getItemCount() {
        return mListData.size();
    }

    /**
     * 布局、viewHolder、bean绑定
     */
    private static class LayoutBeanHolder {
        private Class<?> beanClass;
        private Class<?> holderClass;
        private int layoutRes;

        private LayoutBeanHolder(Class<?> beanClass, int layoutRes) {
            this.beanClass = beanClass;
            this.layoutRes = layoutRes;
        }

        private LayoutBeanHolder(Class<?> beanClass, Class<?> holderClass, int layoutRes) {
            this.beanClass = beanClass;
            this.holderClass = holderClass;
            this.layoutRes = layoutRes;
        }
    }
}

最后我测试了一下:

public class AdapterActivity extends AppCompatActivity{
    private RecyclerView mRecyclerView;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_adapter);
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        final List<Object> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            list.add(new BeanA("我是Aitem-"+i));
        }
        TestAdapter adapter = new TestAdapter<>(list);
        mRecyclerView.setAdapter(adapter);
  }

    @HolderLayoutRes(R.layout.item_layout_1)
    @HolderClass(HolderA.class)
    public static class BeanA{
        String test;
        public BeanA(String test) {
            this.test = test;
        }
    }

   public static class HolderA extends CommonHolder<BeanA> {

        public HolderA(View itemView) {
            super(itemView);
        }

        @Override
        protected void bindData(BeanA data) {
            super.bindData(data);
            setText(R.id.view1, data.test);
        }
    }
}

不知道这样好不好,希望大家留言给给建议,如果可以我会补充TestAdapter封装列表加载状态及头尾View。

上一篇 下一篇

猜你喜欢

热点阅读