英文:
Android ListView items displayed in wrong order
问题
我在更新我的Android应用程序中的ListView时遇到了问题。我已经搜索了解决方案并阅读了多个答案,但没有解决我的问题:
- android-listview-repeating-old-data-after-refresh
- android-requestlayout-improperly-called
- android-listview-not-refreshing-after-notifydatasetchanged
- android-listview-getview-being-called-multiple-times-on-unobservable-views
问题
我有一个ListView,显示2个项目,如下所示:
- 项目1(位置0)
- 项目2(位置1)
从源重新加载数据后,我仍然获得相同的2个项目,但在ListView中显示如下:
- 项目2(位置0)
- 项目2(位置1)
但是,当我点击新列表中的位置0时,它显示项目1的正确数据(点击位置1也显示项目2的正确数据)。
问题是它在位置0和位置1(两次)显示项目2。
以下是更新列表和设置适配器的代码:
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();
...
}
}
以下是适配器代码:
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的宽度和高度都设置为父级ConstraintLayout中的match_parent,其中宽度=0dp(有父级)和高度=match_parent。
查看视频:
屏幕录制
感谢您的所有帮助。
我调试了应用程序。在清除schedulesList.clear()
后,Fragment和BaseAdapter中都包含0个项目。从源中添加所有项目后,schedulesList中包含正确的项目,Fragment和BaseAdapter中也是如此。
我尝试使用clear和addAll将数据填充到适配器中作为单独的List对象。
英文:
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:
- android-listview-repeating-old-data-after-refresh
- android-requestlayout-improperly-called
- android-listview-not-refreshing-after-notifydatasetchanged
- android-listview-getview-being-called-multiple-times-on-unobservable-views
Issue
I have a listview with 2 items displayed like this:
- Item 1 (position 0)
- Item 2 (position 1)
After reloading the data from the source I get the same 2 items, but in the listview it is displayed like this:
- Item 2 (position 0)
- Item 2 (position 1)
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.
答案1
得分: 0
只使用RecyclerView
解决了我所有的问题。但我仍然不知道为什么上面的问题发生了。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论