#Android# 你还在写麻烦的 Adapter 么?

#Android# 你还在写麻烦的 Adapter 么?

这期文章,推荐一个类库 ItemPool,它能很大程度上减少你的 Adapter 数量,它是一个解耦实现,能把 ViewHolder/ItemView 解耦出来。请记住,这让所有 ItemView 变得可复用。

前言

自从 Android 的 RecyclerView 组件发布以来,RecyclerView 成为了 Android 开发中实现容器视图的首选。要实现一个 RecyclerView,必须为其提供一个 RecyclerView.Adapter。我们来看看一个普通 Adapter 的写法:

public class CommonAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private final List<String> list;

    public CommonAdapter(List<String> sampleData) {
        this.list = sampleData;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_test, parent, false);
        return new ViewHolder(item);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof ViewHolder) {
            ((ViewHolder) holder).bindData(list.get(position));
        }
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private TextView text;

        public ViewHolder(View itemView) {
            super(itemView);
            text = (TextView) itemView.findViewById(R.id.textView);
        }

        public void bindData(String data) {
            text.setText(data);
        }
    }
}
这段代码已经十分简单了,但它目前只包含一种类型的 ItemView,当我们需要更多不同的 ItemView 时,需要添加新的 ViewHolder 并更改 onCreateViewHolder() 和 onBindViewHolder() 函数下的代码。

这暂且来说还没有什么大碍。但是当你要实现另外一个类似的 Adapter 时,假设里面有一些在旧 Adapter 中已经出现过的 ItemView,你会发现你没有办法复用之前写过的代码,你只能重新定义一个 Adapter 类并复制旧的 ViewHolder 代码到新的 Adapter 上。这执行起来十分机械,并且当某个 ItemView 发生更改时,你需要同步更改所有对应 Adapter 中的 ViewHolder。


我们需要做点工作把 ViewHolder 代码从 Adapter 中抽离并独立出来,而 ItemPool 能帮你完成这点工作。



ItemPool

使用 ItemPool 后,我们把写 ViewHolder 改变成了写 Item。不同的 Item 用来将不同类型的 Data 映射到相应的 ItemView 上。更重要的是,这些 Item 是可复用的,这意味着你在另外一个 RecyclerView 中也能直接使用该 Item。一个经典的 Item 如下:

public class TestItem extends Item<String> {
    TextView textView;

    @NonNull
    @Override
    public View onCreateItemView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
        View itemView = inflater.inflate(R.layout.item_test, parent, false);
        textView = (TextView) itemView.findViewById(R.id.textView);
        return itemView;
    }

    @Override
    public void onBindItem(@NonNull final RecyclerView.ViewHolder holder, @NonNull String s, ItemEventHandler eventHandler) {
        textView.setText(s);
    }
}

上面除去 IDE 自动生成的代码,实际上仅仅需要自己写 5 行代码。这个 Item 通过 onCreateItemView() 函数来生成某个 ItemView,并挂钩了 String 这个数据类型,然后通过 onBindItem() 函数来将 String 类型的数据传递给 ItemView 进行视图更新。

好的,接下来我们可以给某个 RecyclerView 组装 Item 了,它看起来是这样的:

ItemPool items = new ItemPool();
items.addType(TestItem.class);
items.addType(TestItem2.class);

items.add(new Header());
items.add("A");
items.add("B");

items.attachTo(recyclerView);

可以看出来我们并不要再写 Adapter 了,甚至也不用额外定义一个 DataList 了,它通过以下的工作流程来生成对应的 ItemView:

简而言之就是将指定类型的数据用指定类型的 Item 来展示。这十分容易理解,你只要记住哪个 Item 对应哪个数据类型,并往 ItemPool 中塞数据就行了。

更详细的描述可以移步 README 文档。



末尾

当然,它并不是万能的,一些情况下依然推荐使用 Adapter 实现。但不管怎样,大多数情况下你都能用它,并且为你减少几杯咖啡的工作时间~

(≡ω≡.)

编辑于 2016-08-25