I am having an issue updating the ListView in my Android application. I have searched for the solution and read multiple answers but none solved my issue:
I have a listview with 2 items displayed like this:
After reloading the data from the source I get the same 2 items, but in the listview it is displayed like this:
However, when I click on the position 0 in new list it shows correct data of Item 1 (click on position 1 it also shows correct data of Item 2).
The problem is that it displays Item 2 on position 0 and on position 1 (twice).
Here is the code where list is updated and adapter is setup:
public class FishTankFragment extends DeviceFragment {
...
private final List<FishTankStatus.Schedule> schedulesList = new ArrayList<>();
private ScheduleAdapter scheduleAdapter;
...
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
scheduleAdapter = new ScheduleAdapter(view.getContext(), schedulesList);
screenBinding.lvSchedules.setAdapter(scheduleAdapter);
screenBinding.lvSchedules.setOnItemClickListener((parent, view1, position, id) -> {
new ScheduleItemClickListener(this.getContext(), schedulesList.get(position), position);
});
...
}
@Override
public <T> void onResponse(T responseObject) {
...
schedulesList.clear();
schedulesList.addAll(data.getSchedules());
scheduleAdapter.notifyDataSetChanged();
...
}
Here is Adapter code:
public class ScheduleAdapter extends BaseAdapter {
private ScheduleItemBinding itemBinding;
private final List<FishTankStatus.Schedule> schedules;
private final Context context;
public ScheduleAdapter(@NonNull Context context, @NonNull List<FishTankStatus.Schedule> objects) {
this.context = context;
schedules = objects;
}
@Override
public int getCount() {
return schedules.size();
}
@Override
public FishTankStatus.Schedule getItem(int position) {
return schedules.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
itemBinding = ScheduleItemBinding.inflate(LayoutInflater.from(context));
view = itemBinding.getRoot();
}
if (!schedules.isEmpty()) {
String start = StringUtils.printTime(schedules.get(position).getStart());
String end = StringUtils.printTime(schedules.get(position).getEnd());
itemBinding.tvScheduleStart.setText(start);
itemBinding.tvScheduleEnd.setText(end);
FishTankStatus.Schedule schedule = schedules.get(position);
for (String device : schedule.getDevices()) {
switch (device) {
case "something":
itemBinding.ivYellowlightIcon.setVisibility(View.VISIBLE);
break;
case "something 1":
itemBinding.ivBluelightIcon.setVisibility(View.VISIBLE);
break;
case "something 2":
itemBinding.ivAirIcon.setVisibility(View.VISIBLE);
}
}
if (schedules.get(position).getActive()) {
ColorStateList white = ColorStateList.valueOf(
view.getResources().getColor(R.color.white, view.getContext().getTheme()));
itemBinding.lySchedule.setBackground(ResourcesCompat.getDrawable(view.getResources(),
R.drawable.rectangle_p_light_8,
view.getContext().getTheme()));
...
}
}
return view;
}
}
ListView has width and height set to match_parent in parent ConstraintLayout where width=0dp (has parent) and height=match_parent
See the video: screen recording
Thank you for all the help.
I debugged the app. After clearing schedulesList.clear()
it contained 0 items in Fragment and also in BaseAdapter. After addAll items from the source it contained correct items in schedulesList both in Fragment and BaseAdapter.
I tried to fill the data in Adapter as separate List object using clear and addAll.
I will answer my own question for the future visitors...
Just use RecyclerView
It solved all my issues. But I still do not know why the above problem happened.