为何在MainActivity调用TSDataAdapter的getAllList返回空ArrayList
问题根源
getView()仅在列表项进入可视区域时才会触发,你提前在MainActivity调用getAllList()时,大部分列表项还没执行过getView()逻辑,自然返回空列表。- 就算列表完全渲染完,
getView()会在列表滚动时反复触发(列表项复用机制),你每次调用都执行allList.add(),最终会得到大量重复的无效数据,不符合预期。 - 你直接在TSData中持有Chronometer控件引用是错误做法:列表项复用会导致旧的控件引用指向其他列表项,后续操作计时器会出现串项bug。
修复方案
- 用ViewHolder模式优化列表性能,避免每次
getView()都重复查找控件 - 用SparseArray存储每个位置对应的计时器实例,避免重复添加、数据重复的问题
- 提前初始化数据源,不要在
getView()里填充主数据列表
修改后的参考代码:
public class TSDataAdapter extends ArrayAdapter<TSData> { private ArrayList<TSData> allList; // 存储每个position对应的计时器实例 private SparseArray<Timer> positionTimerMap = new SparseArray<>(); public TSDataAdapter(Context context, int resource, ArrayList<TSData> tsdList) { super(context, resource, tsdList); // 直接复用传入的数据源,不需要新建空列表 allList = new ArrayList<>(tsdList); } static class ViewHolder { TextView subTitleTextView; TextView countTextView; Chronometer chr; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_element, parent, false); holder = new ViewHolder(); holder.subTitleTextView = convertView.findViewById(R.id.titleTextView); holder.countTextView = convertView.findViewById(R.id.countTextView); holder.chr = convertView.findViewById(R.id.chronometer); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } TSData currentData = getItem(position); String subTitle = currentData.getSubTitle(); int count = currentData.getCount(); // 仅当该位置没有存储计时器时才新建,避免重复创建 if (positionTimerMap.get(position) == null) { Timer timer = new Timer(holder.chr); positionTimerMap.put(position, timer); // 如果你需要把计时器存到TSData里,直接更新当前data对象即可,不用新建add currentData.setTimer(timer); } holder.subTitleTextView.setText(subTitle); holder.countTextView.setText(Integer.toString(count)); return convertView; } public ArrayList<TSData> getAllList() { return allList; } // 也可以单独提供获取计时器的方法 public Timer getTimerByPosition(int position) { return positionTimerMap.get(position); } }
如果你需要在列表还没滚动到对应项时就拿到计时器,不要依赖getView的触发逻辑,建议把计时器的初始化逻辑提前放到数据源构造的阶段,不要和View的渲染逻辑绑定。
内容的提问来源于stack exchange,提问作者SmokeyRon
相关产品推荐
相关产品推荐

