web-dev-qa-db-ja.com

ViewHolderでのバインド

これは理論的な質問になります。

誰もがアプリの多くの部分で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);
     }
}

これでb​​indメソッドを追加できます:

public void bind(App app) {
     nameText.setText(app.getName());
}

いいパターンですか?

別の解決策は、ViewModelを使用することです。 RecyclerViewにはさまざまなアイテムがあるため、アダプターには、すべてのViewModelの基本クラスであるクラスのリストを含めることができます。

したがって、基本的なクラスは次のとおりです。

class RecyclerViewItem {}

アプリのViewModelであるクラスです。

class AppRecyclerViewItem extends RecyclerViewItem {

     App app;

     ...
}

アダプターには、RecyclerViewItemsのリストがあります。

class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    List<RecyclerViewItem> items;

    ...
}

したがって、このアプローチ(つまり、ViewModelを使用する)では、ViewHolderまたはViewModelにバインドメソッドを追加する方がよいでしょうか?

12
Nominalista

私はあなたの解決策のどれも良いとは言えません。 1つ目は、アダプターで1回のみ表示されるアイテムにのみ有効です。 ViewHolder内の行を埋めるメソッドを作成することは、異なるタイプのViewHoldersが大きくなり、RecyclerView.Adapterがどんどん行を増やすため、良い解決策ではありません。

2番目の方法も良くありません。モデルはモデルです。アプリケーションのビジネスロジックではなく、データのみを含める必要があります。

Ieに登録されるRecyclerView.Adapterをクリーンに保ち、ViewHolderを作成してデリゲートにデータを入力するロジックを渡すソリューションを提案します。 RecyclerView.Adapterコンストラクタ。このテクニックについては、さらに詳しく説明します ここ

このように、さまざまなViewHolderを1つでも登録しても、RecyclerView.Adapterに定型文が追加されることはありませんが、RecyclerView.Adapter行の作成と入力のロジックはこれらのデリゲートに委任されます。

しかし、それは単なる提案です。

8
R. Zagórski

デリゲートを使用する優れたソリューションがあります- http://hannesdorfmann.com/Android/adapter-delegates であり、DataBindingにも使用できます(簡単な変更で 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
Roman_D

私のアプリでは、次のようなものを使用しています。

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
Pato94