I have a VerticalGridView
that is using a RecyclerView.Adapter
to populate the elements. I have discovered that the onBindViewHolder()
method does not get called if the potential element is off of the viewport. Unfortunately, this is causing a NullPointerException
from a different method because I am catching a TextView
reference in the onBindViewHolder()
method and passing it to an outside variable for later manipulation.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.txtCategoryName.setText(categories.get(position).getStrCategory());
categories.get(position).setTxtViewReference(viewHolder.txtCategoryDefectTotal);
viewHolder.categoryBoxRoot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(CategoryListItem catItem : categories){
if(catItem.getStrCategory().equals(viewHolder.txtCategoryName.getText())){
int index = Defects.getInstance().getCategories().indexOf(catItem) + 1;
MainInterface.grids.get(index).bringToFront();
MainInterface.grids.get(index).setVisibility(View.VISIBLE);
for(VerticalGridView grid : MainInterface.grids){
int gridIndex = MainInterface.grids.indexOf(grid);
if(gridIndex != index){
grid.setVisibility(View.INVISIBLE);
}
}
break;
}
}
}
});
From what I understand, the reference to the TextView
gets created when the Viewholder
object is instantiated.
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView txtCategoryName;
public TextView txtCategoryDefectTotal;
public View categoryBoxRoot;
public ViewHolder(View itemView) {
super(itemView);
txtCategoryName = (TextView) itemView.findViewById(R.id.textViewCategoryName);
txtCategoryDefectTotal = (TextView) itemView.findViewById(R.id.textViewCategoryTotalDefects);
categoryBoxRoot = itemView.findViewById(R.id.root_category_box);
}
}
Is there a way to force onBindViewHolder()
to be called on all elements at least one time when the Adapter
is instantiated?
I attempted the suggestions here without any success.
I understand that forcing onBindViewHolder()
on all elements would work against the whole purpose of the RecycleView.Adapter. Thus, I am open to any other suggestions on how I can catch that TextView
reference.
As a temporary fix to this problem, I am able to use a try catch block around the method that generates the NullPointerException
. However, I am concerned that the lack of the reference means I could introduce errors in the future.
The easiest solution for this problem is to scroll down to the bottom of the grid and then back up to the top. This cannot be done in the onCreate()
method though because the grid is not technically visible at that time. Instead, it should be called in the onResume()
method of the activity.
@Override
public void onResume(){
super.onResume();
VerticalGridView defectGrid = grids.get(0);
RecyclerView.Adapter adapter = defectGrid.getAdapter();
defectGrid.smoothScrollToPosition(adapter.getItemCount()-1);
defectGrid.smoothScrollToPosition(0);
}
This was a good attempt at a solution but unfortunately it still does not work. While it does get the reference to make the method work, it does NOT necessarily have the right reference. I found that the reference can end up pointing at a different TextView as the RecycleView.Adapter reuses views to display them in different areas.
SOLUTION:
Mark Keen was right when he said to use notifyDataSetChanged()
. I got it to work by fixing my onBindViewHolder()
method to work properly.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.txtCategoryName.setText(categories.get(position).getStrCategory());
viewHolder.txtCategoryDefectTotal.setText(String.valueOf(categories.get(position).getTotalDefectsInCategory()));
}
I also changed my data object so it holds an int value instead of a reference to the TextView
since the above proved that reference was invalid. Finally, I added a call to my Adapter
when I pressed my custom back button.
grids.get(0).getAdapter().notifyDataSetChanged();
Thank you everyone who contributed!
wrap your RecyclerView
in a NestedScrollView
that will force all the items to be bound in advance.
<androidx.core.widget.NestedScrollView
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvGrid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false" />
</androidx.core.widget.NestedScrollView>
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