Fred Fred - 3 months ago 19
Android Question

Can/should RecyclerView.Adapter have access to the ViewHolders?

I have an

EditText
in each
View
, and in
onViewRecycled(.)
I update the item in the
Adapter
with any user input. For the purpose of maintaining the information when scrolling
Views
out of and back into view.

However, I realised that with this solution it's a bit of a hassle to retrieve the information that has been modified but not recycled. I solved this by adding each
ViewHolder
to a separate list in the
Adapter
(added in
onCreateViewHolder(.)
), since I couldn't find a simpler way to update the
Views
on the screen.

Is there any reason not to do this; let the
Adapter
have direct access to the
ViewHolders
? I.e. are there any better ways to call a function on all
Views
currently in existance?

Edit:

public class AdapterRv extends Adapter<AdapterRv.MyViewHolder> {
private List<Item> items;
private List<MyViewHoders> viewHolders;

public AdapterRv(List<Item> inItems) {
...

viewHolders = new ArrayList<>();
}

public class MyViewHolder extends RecyclerView.ViewHolder {
private EditText text;
private Item item;

private MyViewHolder(View inView) {
...
}

public void bindItem(Item inItem) {
...
}
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup inParent, int inViewType) {
...

if (!viewHolders.contains(tmpHolder)) {
viewHolders.add(tmpHolder);
}

...
}

....

@Override
public void onViewRecycled(MyViewHolder inViewHolder) {
saveView(inViewHolder.item, inViewHolder.text.getText().toString());
}

private void saveViews() {
for (MyViewHolder tmpViewHolder : viewHolders) {
saveView(tmpViewHolder.item, tmpViewHolder.text.getText().toString());
}
}

private void saveView(Item inItem, String inNewText) {
if (inItem.getText().equals(inNewText)) {
return;
}
inItem.setText(inNewText);
}

public List<Item> fetchTexts() {
saveViews();
return items;
}
}

Answer

The purpose of the RecyclerView.Adapter is only to create ViewHolder instances and provide them with data, but it is the RecyclerView itself that requests holders and manages them.

The purpose of the ViewHolder is, as it name suggests, to hold the item's view hierarchy so the Views can be cached and reused by the RecyclerView. Hence, the adapter should only create and bind the correct data to holders, and it is recommended to not store any references to holders inside the adapter, since you only need the reference to holder in the onBindViewHolder(ViewHolder holder, int position method, where it is provided by the RecyclerView. It's also vice-versa, the view holders don't need a reference to the adapter, so your MyViewHolder should be marked static.

If you need to operate on recycler's views, the RecyclerView has plenty of methods in it's API, such as findViewHolderForLayoutPosition(int position), getChildViewHolder(View child) etc. You can also set listeners for observing scroll, item touch, view attach state etc. changes. See the documentation for the RecyclerView

So, if you need to access and manipulate the views (ie. call the function on all of recycler's views), do it through the RecyclerView and not the adapter, because it's the recycler that manages them - adapter only provides data.

Comments