This is my first attempt at data-binding with a RecyclerView but not my first use of RecyclerView itself.
For some reason none of the adapter methods are called - not even getItemCount(). It could be a stupid problem with my RecyclerView and nothing to do with the data binding at all but I can't see anything wrong.
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);
Adapter:
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; } } }
profile_badge_row.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>
I have checked and there is definitely data there. What have I missed?
=====================
Update:
From what I can tell RecyclerView simply doesn't work inside a Data Binding layout. I created a separate layout with just my RV and it worked perfectly. As soon as I included it with my main layout it ceased to work.
Not sure if this is a bug or a feature.
So, I thought that maybe if I make it a custom view maybe it will work and it does. My problem is I don't know how to pass a value into my custom view.
I looked here but couldn't figure out exactly what he means. This is my code in the custom view.
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);
This gives a message that ProfileBadgesLayoutBinding is not found.
In your 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; }
And add the binding in your Item View
public class BadgeBindingHolder extends RecyclerView.ViewHolder{ private ProfileBadgeRowBinding binding; public BadgeBindingHolder(View rowView, ProfileBadgeRowBinding binding) { super(rowView); this.binding = binding; } ... }
And in the bindToViewHolder
set the variable
@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 }
If you want to access a view, add an id to a view in your 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:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </layout>
And then you can access the id's in your bindToViewHolder
@Override public void bindToViewHolder(RecyclerView.ViewHolder viewHolder) { ProfileBadgeRowBinding binding = ((BadgeBindingHolder) viewHolder).binding; binding.setVariable(BR.badge, badge); binding.executePendingBindings(); binding.image.setImage(...); }
More about custom views https://developer.android.com/topic/libraries/data-binding/index.html#dynamic_variables
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With