Android DataBinding in RecyclerView.ViewHolders with different layouts

若如初见. 提交于 2019-12-30 09:35:39

问题


I'm trying to use androids databinding feature in new project and so far very happy with it.

But now i came across a problem in my recyclerviews viewholder.

My viewholder uses different layouts (based on the viewtype when it gets created)

public MediaViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
     switch(viewType){
          case HEADER: 
             int layout = R.layout.item_media_header;
             break;
          case DEFAULT: 
             int layout = R.layout.item_media_default;
             break;
          case SMALL: 
             int layout = R.layout.item_media_small;
             break;
     }
     View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
     return new MediaViewHolder(v);
}

So all of those 3 layouts have the same views in it, only arranged differently. So the binding of the model to the views is the same.

Anyways, based on those layouts android creates

  • ItemMediaHeaderBinding
  • ItemMediaDefaultBinding
  • ItemMediaSmallBinding

Which sucks since it would force me to create 3 different ViewHolder classes or instantiate the right binding Class by checking which layout is used.

Is there a best practice for this case? Is there a possibility to simply create a superclass for those three binding classes like "ItemMediaBinding".

Thanks in advance.


回答1:


So, what I ended up doing, was to create a BaseViewHolder.class, create other ViewHolder classes that extend this BaseViewHolder, so that my RecyclerView.Adapter still looks clean, because I ended up with something like this as a ViewHolder:

public class BaseVH extends RecyclerView.ViewHolder {
    private ViewDataBinding mBinding;

    public BaseVH(ViewDataBinding mBinding) {
        super(mBinding.getRoot());
        this.mBinding = mBinding;
    }

    public void displayPost(final NewsItem post) {
        PostItemViewModel vm = new PostItemViewModel();
        vm.getPost().set(post);
        mBinding.setVariable(BR.viewModel, vm);
    }
}

public class TextPostVH extends BaseVH {
    private final PostTextBinding mBinding;

    public TextPostVH(final PostTextBinding binding) {
        super(binding);
        mBinding = binding;
    }

    //Have a method like this in the BaseVH.class
    @Override
    public void displayPost(final NewsItem post) {
        if (mBinding.getViewModel() == null) {
            mBinding.setViewModel(new PostItemViewModel());
        }
        mBinding.getViewModel().getPost().set(post);
    }
}

So you can simply call in the onBindViewHolder:

@Override
public void onBindViewHolder(final BaseVH holder, final int position) {
    //only a ViewHolder containing ads has to be filtered, the others work with displayPost()
    if (holder instanceof AdVH){
        holder.displayPost(mPosts.get(position));
        ((AdVH) holder).displayAd();
    } else {
        holder.displayPost(mPosts.get(position));
    }
}

You can specify the Binding class names in your layouts in the data-tag:

 <data class="PostTextBinding" />

But I don't think that you are allowed to use the same class names in different layouts. You can find my (sample) project at GitHub.

Another solution is explained here on Github. They have created a (really) universal RecyclerView.Adapter, but I found this... a little too much for me at this moment.




回答2:


@Amylinn is right, that really do for you, and you can make it even much easy:

// Only one ViewHolder at all
public class BaseVH extends RecyclerView.ViewHolder {
    private ViewDataBinding mBinding;

    public BaseVH(ViewDataBinding mBinding) {
        super(mBinding.getRoot());
        this.mBinding = mBinding;
    }
    public ViewDataBinding() {
        return mBinding;
    }
}

In the onBindViewHolder:

@Override
public void onBindViewHolder(final BaseVH holder, final int position) {
   // Just use "model" as name in any layouts
   holder.getBunding().setVariable(BR.model, mPosts.get(position));
}

But you still has to create view holder with different layout in onCreateViewHolder

Or if you like using delegate, you can look at this approach - https://github.com/drstranges/DataBinding_For_RecyclerView




回答3:


I write a library 😊:The UniqueAdapter With DataBinding

UniqueAdapter

just use the method:

public abstract boolean setVariable(int variableId, Object value);

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if(holder instanceof UniqueViewHolder) {
        ItemModel item = getItem(position);
        UniqueViewHolder vh = ((UniqueViewHolder) holder);
        vh.dataBinding.setVariable(com.github.captain_miao.uniqueadapter.library.BR.viewModel, item);
        if (mPresenter != null) {
            vh.dataBinding.setVariable(com.github.captain_miao.uniqueadapter.library.BR.presenter, mPresenter);
        }
        vh.dataBinding.executePendingBindings();
    }
}


来源:https://stackoverflow.com/questions/38161724/android-databinding-in-recyclerview-viewholders-with-different-layouts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!