RecyclerView 多布局适配器
在项目中难免会遇到多种item的列表。功能实现也很简单,大概思路就是通过覆写getItemViewType ,动态的分出类型 然后创建不同的ViewHolder,实现我们的功能。但是这是常规套路,如果item类型太多,难免Adapter代码臃肿,难以维护。就拿目前开发的项目来说,有6种单据,每种单据类型展示的item都不一样。于是,便决定“优化”一下代码。
反复考虑后,我的思路是,将创建和绑定数据这部分业务逻辑抽象出去,通过依赖Adapter原有的“生命周期”来调用具体实现业务逻辑的对象,废话不多说,代码实现也许更直观一些。
首先定义实体模拟一下项目的需求:
`
public abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
`
我们假设每一种动物为不同的ItemViewType。
然后定义接口
`
public interface Adapter {
/**
* 创建适配器
*
* @param parent
* @return
*/
@NonNull
RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
/**
* 绑定数据
*/
void onBindViewHolder(@NonNull T items, @NonNull RecyclerView.ViewHolder holder, int position);
}
`
具体实现逻辑的Adapter类型
`
public class CatAdapter implements Adapter> {
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_cat, parent, false);
return new CatViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull List items, @NonNull RecyclerView.ViewHolder holder, int position) {
Cat cat = items.get(position);
((CatViewHolder) holder).mName.setText(cat.getName());
}
static class CatViewHolder extends RecyclerView.ViewHolder {
TextView mName;
public CatViewHolder(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.tv_name);
}
}
}
public class DogAdapter implements Adapter> {
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_dog, parent, false);
return new DogViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull List items, @NonNull RecyclerView.ViewHolder holder, int position) {
Dog dog = items.get(position);
((DogViewHolder) holder).mName.setText(dog.getName());
}
static class DogViewHolder extends RecyclerView.ViewHolder {
TextView mName;
public DogViewHolder(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.tv_name);
}
}
}
`
最后,是主适配器,通过主适配器去实现具体调用
`
public class MainAdapter extends RecyclerView.Adapter {
private List mAnimals;
private SparseArrayCompat mCompat;
private static final int TYPE_CAT = 0;
private static final int TYPE_DOG = 1;
public MainAdapter(@Nullable List animals) {
mAnimals = animals;
mCompat = new SparseArrayCompat<>();
mCompat.put(TYPE_CAT, new CatAdapter());
mCompat.put(TYPE_DOG, new DogAdapter());
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return mCompat.get(viewType).onCreateViewHolder(parent);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Adapter adapter = mCompat.get(holder.getItemViewType());
adapter.onBindViewHolder(mAnimals, holder, position);
}
@Override
public int getItemCount() {
return mAnimals.size();
}
@Override
public int getItemViewType(int position) {
if (mAnimals.get(position) instanceof Cat) {
return TYPE_CAT;
} else if (mAnimals.get(position) instanceof Dog) {
return TYPE_DOG;
}
return super.getItemViewType(position);
}
}
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.rv_animals);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
List animals = new ArrayList<>();
animals.add(new Cat("Tom"));
animals.add(new Cat("Kit"));
animals.add(new Dog("mendou"));
animals.add(new Dog("taidi"));
animals.add(new Cat("no"));
mRecyclerView.setAdapter(new MainAdapter(animals));
}
}
`
ok,可以发现主适配器精简了不少。通过统一的接口,我们把具体的业务逻辑,交给了具体的类去实现,从而达到解耦的目地。
然而,本来到这里我的代码优化已经完成了,但是同事却说,这里的类型判断好讨厌,还得去定义不同的类型。于是,我又想能不能把具体的类型判断也交给具体的类去实现呢?
ok,不妨再讲代码升级一下,让主Adapter更简化一些,其余的工作都交给代理去做。我们不妨定义一个代理类,让它去处理具体该调用哪一个业务类。
这里接口也多加两个函数
`
public interface AdapterDelegate {
/**
* 获取类型
*
* @return
*/
int getItemViewType();
/**
* 判断是否为当前类型
*
* @param items
* @param position
* @return
*/
boolean isForViewType(@NonNull T items, int position);
/**
* 创建适配器
*
* @param parent
* @return
*/
@NonNull
RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
/**
* 绑定数据
*/
void onBindViewHolder(@NonNull T items, int position, @NonNull RecyclerView.ViewHolder holder);
}
`
定义一个抽象类返回具体类型
`
public abstract class AbsAdapterDelegate implements AdapterDelegate {
public int viewType;
public AbsAdapterDelegate(int viewType) {
this.viewType = viewType;
}
@Override
public int getItemViewType() {
return viewType;
}
}
`
具体的业务类
`
public class CatAdapter extends AbsAdapterDelegate> {
public CatAdapter(int viewType) {
super(viewType);
}
@Override
public boolean isForViewType(@NonNull List items, int position) {
return items.get(position) instanceof Cat;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_cat, parent, false);
return new CatViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull List items, int position, @NonNull RecyclerView.ViewHolder holder) {
Cat cat = (Cat) items.get(position);
((CatViewHolder) holder).mName.setText(cat.getName());
}
static class CatViewHolder extends RecyclerView.ViewHolder {
TextView mName;
public CatViewHolder(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.tv_name);
}
}
}
public class DogAdapter extends AbsAdapterDelegate> {
public DogAdapter(int viewType) {
super(viewType);
}
@Override
public boolean isForViewType(@NonNull List items, int position) {
return items.get(position) instanceof Dog;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_dog, parent, false);
return new DogViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull List items, int position, @NonNull RecyclerView.ViewHolder holder) {
Dog dog = (Dog) items.get(position);
((DogViewHolder) holder).mName.setText(dog.getName());
}
static class DogViewHolder extends RecyclerView.ViewHolder {
TextView mName;
public DogViewHolder(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.tv_name);
}
}
}
`
业务实现类管理器,主要交给它来处理,具体应该调用哪一个业务类
`
public class AdapterDelegatesManager {
private SparseArrayCompat> delegates = new SparseArrayCompat<>();
public void addDelegate(@NonNull AdapterDelegate delegate) {
int viewType = delegate.getItemViewType();
if (delegates.get(viewType) != null) {
throw new IllegalArgumentException("Already registered AdapterDelegate is " + delegates.get(viewType));
}
delegates.put(viewType, delegate);
}
public int getItemViewType(@NonNull T items, int position) {
if (items == null) {
throw new NullPointerException("Items datasource is null!");
}
int delegatesCount = delegates.size();
for (int i = 0; i < delegatesCount; i++) {
AdapterDelegate delegate = delegates.valueAt(i);
if (delegate.isForViewType(items, position)) {
return delegate.getItemViewType();
}
}
throw new IllegalArgumentException(
"No AdapterDelegate added that matches position=" + position + " in data source");
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
AdapterDelegate adapterDelegate = delegates.get(viewType);
if (adapterDelegate == null) {
throw new NullPointerException("No AdapterDelegate added for ViewType " + viewType);
}
return adapterDelegate.onCreateViewHolder(parent);
}
public void onBindViewHolder(@NonNull T items,
@NonNull RecyclerView.ViewHolder viewHolder, int position) {
AdapterDelegate delegate = delegates.get(viewHolder.getItemViewType());
if (delegate == null) {
throw new NullPointerException(
"No AdapterDelegate added for ViewType " + viewHolder.getItemViewType());
}
delegate.onBindViewHolder(items, position, viewHolder);
}
}
`
最后是我的主Adapter
public class AnimalAdapter extends RecyclerView.Adapter {
private List mAnimals;
private AdapterDelegatesManager> mDelegatesManager = new AdapterDelegatesManager<>();
public AnimalAdapter(List animals) {
this.mAnimals = animals;
mDelegatesManager.addDelegate(new DogAdapter(0));
mDelegatesManager.addDelegate(new CatAdapter(1));
}
@Override
public int getItemViewType(int position) {
return mDelegatesManager.getItemViewType(mAnimals, position);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return mDelegatesManager.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
mDelegatesManager.onBindViewHolder(mAnimals, holder, position);
}
@Override
public int getItemCount() {
return mAnimals.size();
}
}
调用
`
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.rv_animals);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
List animals = new ArrayList<>();
animals.add(new Cat("Tom"));
animals.add(new Cat("Kit"));
animals.add(new Dog("mendou"));
animals.add(new Dog("taidi"));
animals.add(new Cat("no"));
mRecyclerView.setAdapter(new AnimalAdapter(animals));
}
}
`
ok,思路几乎还是不变的。然后通过代理模式让我们的代理类去处理到底该调用哪一个业务类,而具体ViewType也交由具体的业务类去实现。充分达到解耦的目地,更加符合高内聚低耦合的设计规范。
具体代码在这里:https://github.com/qq605088820/delegateadapter.git