CommonViewHolder 先上一下这个全世界都在用的代码
public class CommonViewHolder extends ViewHolder { private SparseArray<View> sparseArray = null; public CommonViewHolder(View itemView) { super(itemView); } public View getView(int viewId) { if (sparseArray == null) { sparseArray = new SparseArray<>(); } View v = null; View viewGot = sparseArray.get(viewId); if (viewGot == null) { v = itemView.findViewById(viewId); sparseArray.put(viewId, v); return v; } else { return viewGot; } } public CommonViewHolder setText(int layoutId, String s) { TextView tv = (TextView) getView(layoutId); tv.setText(s); return this; } public CommonViewHolder setImageBitmap(Context context, int layoutId, int drawableId) { ImageView iv = (ImageView) getView(layoutId); iv.setImageBitmap(((BitmapDrawable)context.getResources().getDrawable(drawableId)).getBitmap()); return this; } public CommonViewHolder glide(Context context, int layoutId, String picUrl) { Glide.with(context).load(picUrl).into((ImageView)getView(layoutId)); return this; } public CommonViewHolder setOnClickListener(int layoutId, View.OnClickListener l) { getView(layoutId).setOnClickListener(l); return this; } public CommonViewHolder setOnClickListener(View.OnClickListener l) { itemView.setOnClickListener(l); return this; } }
下面的注解打造的Adapter用的人就几乎没有了,你可以从这里开启你的旅程
注解的声明
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ItemLayoutId { int itemLayoutId() default -1; }
CommonAdapter
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<CommonViewHolder>{ @Override public CommonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Context context = parent.getContext(); return new CommonViewHolder(LayoutInflater.from(context).inflate(getClass().getAnnotation(ItemLayoutId.class).itemLayoutId(), parent, false)); } @Override public void onBindViewHolder(CommonViewHolder holder, int position) { onBindViewHolder(holder, getDataSource().get(position), position); } @Override public int getItemCount() { List<T> dataSource = getDataSource(); return dataSource == null ? 0 : dataSource.size(); } protected abstract List<T> getDataSource(); protected abstract void onBindViewHolder(CommonViewHolder holder, T t, int position); }
使用
@ItemLayoutId(itemLayoutId = R.layout.item_rv_type) class Adapter extends CommonAdapter<HomeEntity.ListCategoryInfoVoBean> { @Override protected List<HomeEntity.ListCategoryInfoVoBean> getDataSource() { return typeList; } @Override protected void onBindViewHolder(CommonViewHolder holder, HomeEntity.ListCategoryInfoVoBean listCategoryInfoVoBean, int position) { final String shopName = listCategoryInfoVoBean.getCategory_name(); String shopIcon = listCategoryInfoVoBean.getPicture(); holder.setText(R.id.tv_type, shopName); ImageView ivIcon = (ImageView) holder.getView(R.id.iv_icon); Glide.with(context).load(shopIcon).apply(RequestOptions.bitmapTransform(new CircleCrop())).into(ivIcon); ivIcon.setOnClickListener(v -> homeFragment.onServiceTypeItemClick(shopName)); } }
下面说几句废话
在我能力尚弱的时候,我看了鸿洋的封装,能看懂,但是始终不明白,为啥我就想不出来应该这样封装。随着封装的东西多了,面向对象的思维深了,开始明白了。封装的思路是这样形成的:
基本上都是写了很多的重复的代码之后才意识到要封装的。
封装是循序渐进的,一点一点优化,可能今天优化了这个,明天优化了那个,随着时间流逝,封装也会趋于完美,所以封装是一个阶段性很强的操作。
最后发现要封装的地方,这里形成的思维就是,ViewHolder首先是可以复用的,这是写了许多ViewHolder后的出来的结论;
然后Adapter有些代码也是可以复用的,比如onCreateViewHolder里的大部分代码都是冗余的,只需要一个item布局id即可,然后数据源的数量一般也是固定的,而且从数据源中根据position拿到单个元素这个操作也是可以封装的,所以采用了泛型进行一个简化。
最后发现用返回一个方法的形式返回item布局id还是显得有些冗余,所以就采用了注解。
到这里,一个正常情况下的adapter就封装完毕了,只有两个方法,取得数据源,和绑定数据。
注意,这只是正常情况下的adapter,多item type的情况显然不适用,所以说封装是一步步的。只有产生了新的需求,代码才会冗余;只有编写了一定量的冗余的代码后,才会意识到要进行一个封装。封装不是一口气吃成一个胖子,当然你可以从一开始就把整个所有封装的可能都封装好。但是这样真的不会影响你工作吗?而且前期思考的再好,总会有纰漏,还不如一层一层,递进封装。分层思想,是编程思想中最为荟萃与闪光的一点。
还有一个注意点就是,注解只能封装正常的类型,任何的Object都是不支持的,不然这里会把数据源也封装进去,那就舒服了!