Updated response:
Alternative using the CarItems list:
@OnClick(...)
public void onButtonClicked() {
int size = ((MyCustomAdapter) mRecyclerView.getAdapter()).getItemCount();
for (int i = 0; i < size; i++) {
if (((MyCustomAdapter) mRecyclerView.getAdapter()).isItemChecked(i)) {
// Get each selected item
CarItem carItem = (MyCustomAdapter) mRecyclerView.getAdapter()).getItem(i);
// Do something with the item like save it to a selected items array.
}
}
}
You also can add a getCheckedItems()
method to the adapter:
public List<CarItem> getCheckedItems() {
List<CarItem> checkedItems = new ArrayList<>();
for (int i = 0; i < getItemCount(); i++) {
if (isItemChecked(i)) {
checkedItems.add(getItem(i));
}
}
return checkedItems;
}
and use it from the RecyclerView
like this:
((MyCustomAdapter) mRecyclerView.getAdapter()).getCheckedItems();
Is there some way to return data from the Adapter of the RecyclerView
to the Fragment in which I set it?
In general to manipulate the data from your fragment:
Add the methods below to the adapter and call them from the fragment via the recyclerView casting it to your custom adapter: ((MyCustomAdapter) mRecyclerView.getAdapter()).getItem(...);
public void setListItems(List<CarItem> data) {
this.data = data;
}
public List getListItems() {
return data;
}
@Override
public int getItemCount() {
return this.data.size();
}
public CarItem getItem(int position) {
return data.get(position);
}
public void setItem(CarItem item, int position) {
data.set(position, item);
}
I have a RecyclerView in which in each object of the RecyclerView I
have a checkbox. Each time one of the checkboxes is pressed I would
like to insert data on the Adapter.
Manage multichoice state and saved state
Read this explanation and check this sample app for multichoice.
This library also extends adapter for selection using SparseBooleanArray to save selected items.
Or use this to save the checked state and use it later when button is pressed to only access to the data of the checked items:
public class MyCustomAdapter extends RecyclerView.Adapter<MyCustomAdapter.MyCustomViewHolder> {
private ArrayList<CarItem> data;
private SparseBooleanArray checkedState = new SparseBooleanArray();
public void setCheckedState(int position, boolean checked) {
checkedState.append(position, checked);
}
public boolean isItemChecked(int position) {
return checkedState.get(position);
}
public SparseBooleanArray getCheckedState() {
return checkedState;
}
public void onBindViewHolder(final MyCustomViewHolder holder, final int position) {
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setCheckedState(holder.getAdapterPosition(), isChecked);
//Here I add the data that I want to store
if (isChecked) {
data.set(holder.getAdapterPosition(), holder.getItem());
} else {
data.set(holder.getAdapterPosition(), null);
}
}
});
}
Reason to use adapter position on this related Google I/O 2016 video:
I have created getItem() method to get the data inside
MyCustomViewHolder but I do not know how to return the data to the
Fragment in which I sets the Adapter to the RecyclerView.
Set/get data to/from the view holder
Also these methods can be useful to get the data, perhaps using the setTag()/getTag() mechanism.
viewHolder.itemView.setTag(yourNewData);
/**
* Returns this view's tag.
*
* @return the Object stored in this view as a tag, or {@code null} if not
* set
*
* @see #setTag(Object)
* @see #getTag(int)
*/
@ViewDebug.ExportedProperty
public Object getTag() {
return mTag;
}
/**
* Sets the tag associated with this view. A tag can be used to mark
* a view in its hierarchy and does not have to be unique within the
* hierarchy. Tags can also be used to store data within a view without
* resorting to another data structure.
*
* @param tag an Object to tag the view with
*
* @see #getTag()
* @see #setTag(int, Object)
*/
public void setTag(final Object tag) {
mTag = tag;
}
One time I finished (press a
button on the Fragment that sets the Adapter to the RecyclerView) the
data have to be returned.
I would need extra info about what are you trying to do when the data is returned and the reason you set the adapter to the recyclerview another time here.
findViewHolderForAdapterPosition(int)
/**
* Return the ViewHolder for the item in the given position of the data set. Unlike
* {@link #findViewHolderForLayoutPosition(int)} this method takes into account any pending
* adapter changes that may not be reflected to the layout yet. On the other hand, if
* {@link Adapter#notifyDataSetChanged()} has been called but the new layout has not been
* calculated yet, this method will return <code>null</code> since the new positions of views
* are unknown until the layout is calculated.
* <p>
* This method checks only the children of RecyclerView. If the item at the given
* <code>position</code> is not laid out, it <em>will not</em> create a new one.
*
* @param position The position of the item in the data set of the adapter
* @return The ViewHolder at <code>position</code> or null if there is no such item
*/
public ViewHolder findViewHolderForAdapterPosition(int position) {
if (mDataSetHasChangedAfterLayout) {
return null;
}
final int childCount = mChildHelper.getUnfilteredChildCount();
for (int i = 0; i < childCount; i++) {
final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
if (holder != null && !holder.isRemoved() && getAdapterPositionFor(holder) == position) {
return holder;
}
}
return null;
}
@OnClick(...)
public void onButtonClicked() {
int size = ((MyCustomAdapter) mRecyclerView.getAdapter()).getItemCount();
for (int i = 0; i < size; i++) {
ViewHolder vh = (MyCustomViewHolder) findViewHolderForAdapterPosition(i);
if (vh != null && ((MyCustomAdapter) mRecyclerView.getAdapter()).isItemChecked(i)) {
Object obj = vh.itemView.getTag();
// Manipulate the data contained in this view holder
// but perhaps would be better to save the data in the CarItem
// and don't manipulate the VH from outside the adapter
}
}
}