Reputation: 1749
I am implementing a Nested Recycler View
.
The nested recycler
view is dynamically added for each item when the button is clicked.
I have implemented this function. But when you click the button to add an item,
the item update is only possible through the nested recyclerview's setAdapter()
,
not the notifyDataSetChanged()
Why is this happening? Why isn't it updated with notifyDataSetChanged()
?
At least as far as I know the setAdapter()
should only be called once.
Does it matter if the setAdapter()
is called multiple times?
What I want is to be updated by the notifyDataSetChanged()
, not an setAdapter()
.
But item is updated by the setAdapter()
.
Why?
RoutineModel.java
public class RoutineModel {
String routine;
public ArrayList<RoutineDetailModel> arrayListDetail;
public RoutineModel(String routine) {
this.routine = routine;
}
public String getRoutine() {
return routine;
}
}
RoutineAdapter.java (Nested Recyclerview's Adapter)
public class RoutineAdapter extends RecyclerView.Adapter<RoutineAdapter.ViewHolder> {
ArrayList<RoutineModel> routineItems = new ArrayList<>();
Context context;
public void addItem(RoutineModel item) {
routineItems.add(item);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View itemView = inflater.inflate(R.layout.routine_item, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
RoutineModel curRoutineItem = routineItems.get(position);
holder.setItems(curRoutineItem);
// Set Routine Detail (Nested RecyclerView)
holder.setRoutineDetailRecyClerView();
RoutineDetailAdapter detailAdapter = new RoutineDetailAdapter();
curRoutineItem.arrayListDetail = new ArrayList<>();
curRoutineItem.arrayListDetail.add(new RoutineDetailModel());
holder.routine_detail.setAdapter(detailAdapter);
detailAdapter.addItems(curRoutineItem.arrayListDetail);
// add NestedRecyclerView's item (Dynamically)
holder.addSet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
curRoutineItem.arrayListDetail.add(new RoutineDetailModel());
detailAdapter.addItems(curRoutineItem.arrayListDetail);
holder.routine_detail.setAdapter(detailAdapter); // HERE!!!!!
}
});
}
@Override
public int getItemCount() {
return routineItems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView routine;
Button addSet;
RecyclerView routine_detail;
public ViewHolder(@NonNull View itemView) {
super(itemView);
initViews();
}
private void initViews() {
routine = itemView.findViewById(R.id.routine);
routine_detail = itemView.findViewById(R.id.detail_routine);
addSet = itemView.findViewById(R.id.add_set);
}
private void setItems(RoutineModel routineItem) {
routine.setText(routineItem.getRoutine());
}
public void setRoutineDetailRecyClerView() {
routine_detail.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false));
routine_detail.setHasFixedSize(true);
}
}
}
RoutineDetailModel.java (Nested Recyclerview's Model)
public class RoutineDetailModel {
String set;
String weight;
String reps;
}
RoutineDetailAdapter.java
public class RoutineDetailAdapter extends RecyclerView.Adapter<RoutineDetailAdapter.ViewHolder>{
ArrayList<RoutineDetailModel> items = new ArrayList<>();
public void addItems(ArrayList<RoutineDetailModel> items) {
this.items = items;
notifyDataSetChanged();
}
public ArrayList<RoutineDetailModel> getItem() {
return this.items;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.routine_detail_item, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
RoutineDetailModel item = items.get(position);
holder.setItem(item);
}
@Override
public int getItemCount() {
return items.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView set;
public ViewHolder(@NonNull View itemView) {
super(itemView);
set = itemView.findViewById(R.id.set);
}
private void setItem(RoutineDetailModel item) {
set.setText("TEST");
}
}
}
++++++++++++++++++++++++++++++++++
OnCreateViewHolder
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View itemView = inflater.inflate(R.layout.routine_item, parent, false);
ViewHolder holder = new ViewHolder(itemView);
detailAdapter = new RoutineDetailAdapter();
holder.setRoutineDetailRecyClerView();
holder.routine_detail.setAdapter(detailAdapter);
return holder;
}
Upvotes: 1
Views: 1186
Reputation: 19562
RecyclerView
s work by recycling a handful of ViewHolder
objects, and updating them to display a different item's data. That happens in onBindViewHolder
, which is where you're setting it up to display the data with your holder.setItems(curRoutineItem)
call, right?
But each time you bind a view holder, this is what you're doing:
RoutineModel
for the current positionarrayListDetail
and adding a single, new ``RoutineDetailModel```RoutineDetailAdapter
which only contains that single RoutineDetailModel
, and setting that on the ViewHolder
's RecyclerView
, replacing what was already thereRoutineDetailModel
to the RoutineModel
and adapter (both of which will be cleared and recreated next time onBindViewHolder
is called)So I don't know specifically where your problem lies, but you're not actually storing this state with the added items - it gets wiped every time onBindViewHolder
is called, whenever an item scrolls into view.
If you're saying that you click the button and nothing happens in the RecyclerView
without calling setAdapter
again, then I'm not sure why that would happen - at that point detailAdapter
is referencing the adapter in the recycler view, and you are adding another item (technically replacing its items with the same list of one plus another one).
But if you mean you scroll the list and your items disappear, yeah that's going to happen, because you delete them every time the item scrolls back into view. This stuff looks like data initialisation:
curRoutineItem.arrayListDetail = new ArrayList<>();
curRoutineItem.arrayListDetail.add(new RoutineDetailModel());
and definitely shouldn't be happening in onBindViewHolder
. This stuff:
RoutineDetailAdapter detailAdapter = new RoutineDetailAdapter();
holder.routine_detail.setAdapter(detailAdapter);
is RecyclerView
initialisation and should probably be happening once per recyclerview, in onViewHolderCreated
. Then in onBindViewHolder
you can just call getAdapter
and set the items you want to display.
That might help you with your issue, I'm not sure what you're seeing exactly because I'd expect it to feel pretty broken as it is!
Upvotes: 2