在ViewHolder中绑定

问题描述 投票:0回答:4

这将是理论问题。

作为每个人,我们在应用程序的许多部分都使用 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 中添加绑定方法更好?

android android-recyclerview android-viewholder
4个回答
9
投票

我想说,你们的解决方案都不好。 第一个仅适用于在适配器中仅出现一次的项目。创建一种方法来填充

ViewHolder
内的行并不是一个好的解决方案,因为不同类型的
ViewHolders
会增长,并且您的
RecyclerView.Adapter
会获得越来越多的行。

第二种方法也不好。模型就是模型,应该只包含数据而不包含应用程序的业务逻辑。

我建议一个解决方案来保持

RecyclerView.Adapter
干净,并传递创建
ViewHolder
并向代表填充数据的逻辑,这些逻辑将在 ie 中注册。
RecyclerView.Adapter
构造函数。 这项技术有更多解释这里

这样,即使注册多个不同的

ViewHolder
也不会专门向
RecyclerView.Adapter
添加样板,而是将创建和填充
RecyclerView.Adapter
行的逻辑委托给这些委托人。

但这只是一个建议。


0
投票

对于我的应用程序,我一直在使用这样的东西:

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 的具体子类,


0
投票
http://hannesdorfmann.com/android/adapter-delegates

,它甚至可以用于数据绑定(只需进行简单的更改,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); } }



0
投票

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; // ...

© www.soinside.com 2019 - 2024. All rights reserved.