Связывание данных Android в RecyclerView.ViewHolders с различными макетами

Я пытаюсь использовать функцию привязки данных андроидов в новом проекте и до сих пор очень доволен этим.

Но теперь я столкнулся с проблемой в моем окне просмотра.

Мой видоискатель использует разные макеты (в зависимости от вида, когда он создается)

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);
}

Таким образом, все эти 3 макета имеют одинаковые виды, но расположены по-разному. Так что привязка модели к представлениям одинакова.

В любом случае, на основе этих макетов Android создает

ItemMediaHeaderBindingItemMediaDefaultBindingItemMediaSmallBinding

Какой отстой, так как это заставило бы меня создать 3 разных класса ViewHolder или создать экземпляр правильного связующего класса, проверив, какой макет используется.

Есть ли лучшая практика для этого случая? Есть ли возможность просто создать суперкласс для тех трех классов привязки, как "ItemMediaBinding".

Заранее спасибо.

Ответы на вопрос(3)

@ Amylinn прав, это действительно для вас, и вы можете сделать это даже намного проще:

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

в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));
}

Но вам все еще нужно создать видовой держатель с другим макетом вonCreateViewHolder

Или, если вам нравится использовать делегат, вы можете посмотреть на этот подход -https://github.com/drstranges/DataBinding_For_RecyclerView

 Sam07 сент. 2017 г., 08:19
Этот пост помог мне. Спасибо!
Решение Вопроса

Итак, что я в конечном итоге сделал, было создатьBaseViewHolder.class, создай другиеViewHolder классы, которые расширяют этоBaseViewHolderтак что мойRecyclerView.Adapter все еще выглядит чистым, потому что я закончил с чем-то вроде этого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);
    }
}

Так что вы можете просто позвонить в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));
    }
}

Вы можете указатьBinding class names в вашемlayouts вdata-тег:

 <data class="PostTextBinding" />

Но я не думаю, что вам разрешено использовать одни и те же имена классов в разных макетах. Вы можете найти мой (пример) проекта наGitHub.

Другое решение объясняетсяздесь на Github, Они создали (действительно) универсальныйRecyclerView.Adapter, но я нашел это ... слишком много для меня в данный момент.

 hightower13 июл. 2016 г., 16:13
Спасибо! я не думаю, что он может получить какой-либо очиститель с привязкой данных и как он используется в настоящее время.
 yennsarah13 июл. 2016 г., 21:23
Спасибо. Изучение этого стоило мне много, но я думаю, что оно того стоит. :)

Я пишу библиотеку: уникальный адаптер с привязкой данных

UniqueAdapter

просто используйте метод:

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();
    }
}

Ваш ответ на вопрос