这将是一个理论问题。
每个人都在应用的许多部分使用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方法?
答案 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