RecyclerView和Data Binding不起作用。

24

这是我第一次尝试使用RecyclerView进行数据绑定,但不是我第一次使用RecyclerView。

由于某种原因,适配器方法都没有被调用——甚至是getItemCount()也没有被调用。 这可能是由于我的RecyclerView存在一些愚蠢的问题,与数据绑定无关,但我看不出有什么问题。

       View rootview = inflater.inflate(R.layout.fragment_profile_first, container, false);
    // Initialize recycler view

    RecyclerView badgesRV = (RecyclerView) rootview.findViewById(R.id.badgesRV);
    LinearLayoutManager llm = new LinearLayoutManager(getActivity());
    llm.setOrientation(LinearLayoutManager.HORIZONTAL);
    badgesRV.setLayoutManager(llm);

    BadgeAdapter badgeAdapter = new BadgeAdapter(profileObject.badgesEntity.badges);
    badgesRV.setAdapter(badgeAdapter);

适配器:

    public class BadgeAdapter extends RecyclerView.Adapter<BadgeAdapter.BadgeBindingHolder>{

    private static final int MAX_BADGES_TO_DISPLAY = 5;
    private BadgeObject[] badges;

    public BadgeAdapter(BadgeObject[] badges){
        this.badges = badges;
    }

    @Override
    public BadgeBindingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.profile_badge_row, parent, false);
        BadgeBindingHolder holder = new BadgeBindingHolder(v);
        return holder;
    }

    @Override
    public void onBindViewHolder(BadgeBindingHolder holder, int position) {
        final BadgeObject badgeObject = badges[position];
        holder.getBinding().setVariable(BR.badge, badgeObject);
        holder.getBinding().executePendingBindings();

    }

    @Override
    public int getItemCount() {
        Log.d(TAG, "item count = " + Math.min(MAX_BADGES_TO_DISPLAY, badges.length));
        return Math.min(MAX_BADGES_TO_DISPLAY, badges.length);
    }

    public class BadgeBindingHolder extends RecyclerView.ViewHolder{
        private ViewDataBinding binding;

        public BadgeBindingHolder(View rowView) {
            super(rowView);
            binding = DataBindingUtil.bind(rowView);
        }
        public ViewDataBinding getBinding() {
            return binding;
        }
    }
}

个人资料徽章行.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<data>
    <variable name="badge" type="parseJsonEntities.requestObjects.BadgeObject"/>
</data>

<LinearLayout
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@{badge.badgeImage}"/>

</LinearLayout>

我已经检查过了,数据确实存在。我错过了什么?

=====================

更新:

据我所知,RecyclerView 在 Data Binding 布局中根本无法工作。 我创建了一个只有我的 RV 的单独布局,并且它完美地工作了。 只要我将其包含在主布局中,它就停止工作了。

不确定这是一个错误还是一个功能。

所以,我想也许如果我将其制作为自定义视图,它可能会起作用,而且实际上确实如此。 我的问题是我不知道如何将一个值传递到我的自定义视图中。

我看了这里但是没能完全理解他的意思。 这是我的自定义视图中的代码。

    LayoutInflater inflater = (LayoutInflater)
            context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.profile_badges_layout, this, true);
    ProfileBadgesLayoutBinding binding = ProfileBadgesLayoutBinding.inflate(inflater);

    RecyclerView badgesRV = (RecyclerView) view.findViewById(R.id.badgesRV);

    LinearLayoutManager llm = new LinearLayoutManager(context);
    llm.setOrientation(LinearLayoutManager.HORIZONTAL);
    badgesRV.setLayoutManager(llm);

    BadgeAdapter badgeAdapter = new BadgeAdapter(null);
    badgesRV.setAdapter(badgeAdapter);

这个消息表明ProfileBadgesLayoutBinding没有被找到。


你的片段 XML 在哪里? - Uttam Panchasara
1
“RecyclerView” 与 “DataBinding” 完美配合,许多人都在使用它而没有问题。你能否发布一下你的布局,其中包含了你的 “RecyclerView”?也许是由于其他滚动视图的奇怪行为所导致的。 - yennsarah
1
另外,badge.badgeImage是什么?是一个“资源ID”,还是一个“可绘制对象”..? - yennsarah
2个回答

22

在您的onCreateViewHolder中:

@Override
public BadgeBindingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    ProfileBadgeRowBinding binding = DataBindingUtil.inflate(inflater, R.layout.profile_badge_row, parent, false);
    BadgeBindingHolder holder = new BadgeBindingHolder(binding.getRoot(), binding);
    return holder;
}

在你的Item View中添加绑定

public class BadgeBindingHolder extends RecyclerView.ViewHolder{
    private ProfileBadgeRowBinding binding;

    public BadgeBindingHolder(View rowView, ProfileBadgeRowBinding binding) {
        super(rowView);
        this.binding = binding;
    }

    ...

}

bindToViewHolder 中设置变量。

@Override
public void bindToViewHolder(RecyclerView.ViewHolder viewHolder) {
    ProfileBadgeRowBinding binding = ((BadgeBindingHolder) viewHolder).binding;
    binding.setVariable(BR.badge, badge);
    binding.executePendingBindings(); // This line is important, it will force to load the variable in a custom view
}
如果您想要访问一个视图,需要在xml文件中为该视图添加一个ID。
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable name="badge" type="parseJsonEntities.requestObjects.BadgeObject"/>
    </data>

    <LinearLayout
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>
</layout>

然后你就可以在bindToViewHolder函数中访问这些id了。

@Override
public void bindToViewHolder(RecyclerView.ViewHolder viewHolder) {
    ProfileBadgeRowBinding binding = ((BadgeBindingHolder) viewHolder).binding;
    binding.setVariable(BR.badge, badge);
    binding.executePendingBindings();

    binding.image.setImage(...);
}

更多有关自定义视图的信息,请访问https://developer.android.com/topic/libraries/data-binding/index.html#dynamic_variables


2
谢谢!我的问题是我没有使用binding.executePendingBindings(); 对我来说这看起来不是很明显。非常感谢!!! - Jack'
我在所有适配器中都遇到了很多数据绑定问题,你解决了它。感谢你的答案。 - Priyanka
如果您正在使用DiffUtils并仍然遇到问题,请查看此内容。愚蠢的“submitList”有一个奇怪的逻辑。 - hushed_voice

0

今天做这个要容易得多, 跟着这个例子走:

public class LanguageRecyclerAdapter extends RecyclerView.Adapter<LanguageRecyclerAdapter.LanguageViewHolder> {

    private List<Language> languages;

    public class LanguageViewHolder extends RecyclerView.ViewHolder {

        final LanguageSetItemBinding item;

        public void bind(final Language language) {
            item.setLanguage(language.getName());
            item.setFlag(language.getFlagRes());
            item.getRoot().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
//do somthing if you need
                }
            });
            item.executePendingBindings();
        }

        public LanguageViewHolder(LanguageSetItemBinding itemView) {
            super(itemView.getRoot());
            item =itemView;
        }
    }

    public LanguageRecyclerAdapter(List<Language> languages) {
        this.languages = languages;
    }

    public void onBindViewHolder(LanguageViewHolder holder, int position) {
        Language item = languages.get(position);
        holder.bind(item);
    }

    public LanguageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        LanguageSetItemBinding item = LanguageSetItemBinding.inflate(layoutInflater, parent,false);
        return new LanguageViewHolder(item);
    }

    @Override
    public int getItemCount() {
        return languages.size();
    }

    @Override
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }
}

LanguageSetItemBinding 的 XML 如下,其中包含一个 TextViewImageView

<?xml version="1.0" encoding="utf-8"?>
<layout >
    <data>
        <variable name="language" type="String" />
        <variable name="flag" type="int" />
    </data>

    <android.widget.LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="166dp"
        android:layout_height="166dp"
        android:background="@color/colorWhite"
        android:orientation="vertical"
        android:layout_margin="20dp"
        android:gravity="center">
        <TextView
            android:layout_marginTop="20dp"
            android:gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:text="@{language}"
            android:textColor="@color/colorBlack"
            android:textAlignment="center"/>
        <ImageView
            android:textColor="?attr/errorColor"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:src="@{context.getDrawable(flag)}"
            android:gravity="center"
            android:paddingTop="3dp"/>
    </android.widget.LinearLayout>
</layout>

我有一个包含RecyclerView的Activity,在该Activity的onCreateView中,我将这个RecyclerView连接到我上面创建的适配器:

final ArrayList<Language> lang = new ArrayList(languageList.values());
final LanguageRecyclerAdapter adapter = new LanguageRecyclerAdapter(lang);
mBinding.languageRecyclerView.setAdapter(adapter);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接