在ViewHolder中绑定

时间:2016-10-09 17:21:50

标签: android android-recyclerview android-viewholder

这将是一个理论问题。

每个人都在应用的许多部分使用RecyclerView。有时,RecyclerView包含不同的项目,不仅包括图像,还包括广告,提示等。这就是为什么我们可以在Adapter中使用getViewType()方法。

但是当我们有很多viewTypes并且在Adapter中绑定它不优雅时会出现问题。所以这是一个问题,在ViewHolder中绑定数据是好的和好的模式吗?

假设我们有应用列表。

每个应用都有简洁的名称。我们的ViewHolder看起来像这样:

class AppViewHolder extends RecyclerView.ViewHolder {

     public TextView nameText;

     AppViewHolder(View itemView) {
          super(itemView)
          nameText = (TextView) itemView.findViewById(R.id.text_name);
     }
}

现在我们可以添加bind方法:

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

这是好模式吗?

另一种解决方案是使用ViewModel。因为我们在RecyclerView中有不同的项目,所以我们的适配器可以包含类的列表,它是每个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中添加bind方法?

3 个答案:

答案 0 :(得分:8)

我想说你的解决方案都不好。 第一个仅适用于在适配器中只出现一次的项目。创建一个方法来填充ViewHolder内的行不是一个好的解决方案,因为不同类型的ViewHolders会增长,而RecyclerView.Adapter会获得越来越多的行。

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

我建议一个解决方案,让RecyclerView.Adapter保持清洁并传递创建ViewHolder的逻辑并将数据填充给代表,这些将在ie中注册。 RecyclerView.Adapter构造函数。 更多here

解释了这种技术

这样,即使在不同的ViewHolder上注册,也不会特别向RecyclerView.Adapter添加样板,而是将RecyclerView.Adapter行的创建和填充逻辑委托给这些代理。

但这只是一个建议。

答案 1 :(得分: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的具体子类,

答案 2 :(得分:0)

使用委托 - http://hannesdorfmann.com/android/adapter-delegates有很好的解决方案,它甚至可以用于DataBinding(通过简单的更改https://github.com/drstranges/DataBinding_For_RecyclerView)。通过这种方式,数据不在ViewHolder中而不在RecyclerView Adapter中绑定,但ItemDelegate执行此操作,因此您的代码仍然清晰可读。

遵循此方法,所有使用委托给DelegateManager的视图类型:

    public void test(Class<T> t) {
            T[] a=new T[10];//complie error

        Object array = java.lang.reflect.Array.newInstance(t, 10);//lots of ambiguity
        String[] arrT = (String[]) array;//works if you know the final type

        Object[] anyType = new Object[10];
        for(int i=0;i<10;i++)
               anyType[i] = createObject(t.getName());
        //You will need to cast the Object to your desired type
        }
      static Object createObject(String className) {
          //http://www.java2s.com/Code/Java/Reflection/ObjectReflectioncreatenewinstance.htm
      Object object = null;
      try {
          Class classDefinition = Class.forName(className);
          object = classDefinition.newInstance();
      } catch (InstantiationException e) {
          System.out.println(e);
      } catch (IllegalAccessException e) {
          System.out.println(e);
      } catch (ClassNotFoundException e) {
          System.out.println(e);
      }
      return object;
   }

您的代码将如下所示:

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
相关问题