这将是理论问题。
作为每个人,我们在应用程序的许多部分都使用 RecyclerView。有时RecyclerView包含不同的项目,不仅是图像,还有广告、提示等。这就是为什么我们可以在Adapter中使用getViewType()方法。
但是当我们有很多 viewType 并且在 Adapter 中绑定它并不优雅时,就会出现问题。那么问题来了,在ViewHolder中绑定数据是不是很好的模式?
假设我们有应用程序列表。
为了简单起见,每个应用程序都有一个名称。我们的 ViewHolder 看起来像这样:
class AppViewHolder extends RecyclerView.ViewHolder {
public TextView nameText;
AppViewHolder(View itemView) {
super(itemView)
nameText = (TextView) itemView.findViewById(R.id.text_name);
}
}
现在我们可以添加绑定方法了:
public void bind(App app) {
nameText.setText(app.getName());
}
这个图案好不好?
另一个解决方案是使用 ViewModel。因为我们在 RecyclerView 中有不同的项目,所以我们的 Adapter 可以包含类列表,该类是每个 ViewModel 的基类。
所以基础课是:
class RecyclerViewItem {}
现在是 App 的 ViewModel 类。
class AppRecyclerViewItem extends RecyclerViewItem {
App app;
...
}
我们的适配器只有 RecyclerViewItems 列表:
class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<RecyclerViewItem> items;
...
}
那么使用这种方法(我的意思是使用 ViewModel)是在 ViewHolder 中添加绑定方法更好,还是在 ViewModel 中添加绑定方法更好?
我想说,你们的解决方案都不好。 第一个仅适用于在适配器中仅出现一次的项目。创建一种方法来填充
ViewHolder
内的行并不是一个好的解决方案,因为不同类型的 ViewHolders
会增长,并且您的 RecyclerView.Adapter
会获得越来越多的行。
第二种方法也不好。模型就是模型,应该只包含数据而不包含应用程序的业务逻辑。
我建议一个解决方案来保持
RecyclerView.Adapter
干净,并传递创建 ViewHolder
并向代表填充数据的逻辑,这些逻辑将在 ie 中注册。 RecyclerView.Adapter
构造函数。
这项技术有更多解释这里
这样,即使注册多个不同的
ViewHolder
也不会专门向 RecyclerView.Adapter
添加样板,而是将创建和填充 RecyclerView.Adapter
行的逻辑委托给这些委托人。
但这只是一个建议。
对于我的应用程序,我一直在使用这样的东西:
public abstract class BindableViewHolder<T> extends RecyclerView.ViewHolder {
public BindableViewHolder(View itemView) {
super(itemView);
}
public abstract void bind(T thing);
}
这个想法是将绑定的实现委托给ViewHolder。此解决方案适用于您想要将“同一种对象”绑定到不同视图持有者的情况,但我认为它可以轻松扩展到更一般的情况。 这是一个非常简单的适配器的示例。我想它已经解释清楚了,希望有帮助!
public class ShowsAdapter extends RecyclerView.Adapter<BindableViewHolder<Show>> {
private final DataProvider<Show> showsProvider;
public ShowsAdapter(DataProvider<Show> showsProvider) {
this.showsProvider = showsProvider;
}
@Override
public BindableViewHolder<Show> onCreateViewHolder(ViewGroup parent, int viewType) {
return ShowViewHolder.create(parent);
}
@Override
public void onBindViewHolder(BindableViewHolder<Show> holder, int position) {
holder.bind(showsProvider.get(position));
}
@Override
public int getItemCount() {
return showsProvider.size();
}
}
这里,ShowViewHolder 是 BindableViewHolder 的具体子类,
,它甚至可以用于数据绑定(只需进行简单的更改,https://github.com/drstranges/DataBinding_For_RecyclerView) 。通过这种方式,数据绑定不是在 ViewHolder 中,也不是在 RecyclerView Adapter 中,而是 ItemDelegate 执行此操作,因此您的代码保持清晰易读。 遵循这种方法,所有视图类型都可以委托给 DelegateManager:
public abstract class AbsDelegationAdapter<T> extends RecyclerView.Adapter {
protected AdapterDelegatesManager<T> delegatesManager;
protected T items;
//...
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return delegatesManager.onCreateViewHolder(parent, viewType);
}
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
delegatesManager.onBindViewHolder(items, position, holder);
}
@Override public int getItemViewType(int position) {
return delegatesManager.getItemViewType(items, position);
}
}
你的代码将如下所示:
mAdapter = new BindableAdapter<>(
new UserDelegate(actionHandler), // you can create custom delegate
//new ModelActionItemDelegate<BaseModel>(actionHandler, User.class, R.layout.item_user, BR.user), // or use generic
new AnotherItemDelegate());
哪里
ItemDelegate
可以看起来像这样:
public class UserDelegate extends BaseAdapterDelegate<BaseModel, ItemUserBinding> {
@Override
public boolean isForViewType(@NonNull final List<BaseModel> items, final int position) {
return items.get(position) instanceof User;
}
@NonNull
@Override
public BindingHolder<ItemUserBinding> onCreateViewHolder(final ViewGroup parent) {
// create ViewHolder
return BindingHolder.newInstance(R.layout.item_user, LayoutInflater.from(parent.getContext()), parent, false);
}
@Override
public void onBindViewHolder(@NonNull final List<BaseModel> items, final int position, @NonNull final BindingHolder<ItemUserBinding> holder) {
// Just bind data
final User user = (User) items.get(position);
holder.getBinding().setUser(user);
}
}
class BindableViewHolder<T extends ViewBinding> extends RecyclerView.ViewHolder {
public final T binding;
public BindableViewHolder(@NonNull T binding) {
super(binding.getRoot());
this.binding = binding;
}
}
实施:
public class MyDemoRecyclerAdapter extends RecyclerView.Adapter<BindableViewHolder<LayoutTestBinding>> {
@NonNull
@Override
public BindingViewHolder<LayoutTestBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutTestBinding binding = LayoutTestBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new BindableViewHolder<>(binding);
}
@Override
public void onBindViewHolder(@NonNull BindingViewHolder<LayoutTestBinding> holder, int position) {
final int pos = holder.getAbsoluteAdapterPosition();
final MyItem item = mData.get(pos);
final LayoutTestBinding binding = holder.binding;
// ...