自定义BaseAdapter复用视图出现脏视图问题,求简洁优化方案
解决BaseAdapter视图复用导致的显示异常问题
问题根源
你的代码仅在满足rideId=-1等条件时修改控件状态,但视图复用后,之前被修改过的控件状态会被保留,被其他列表项(比如第一个元素)复用,从而出现不符合预期的显示效果。
简洁解决方案
不需要自行维护视图列表,核心思路是在getView方法中先重置所有控件的默认状态,再根据当前列表项的条件做特殊修改。这样无论视图是否被复用,都会先恢复到初始状态,再适配当前列表项的需求,既保留视图复用的性能优势,又能避免状态混乱。
改造后的示例代码
@Override public View getView(int position, View convertView, ViewGroup parent) { // 保留视图复用逻辑,这是滚动流畅性的关键 if(convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false); } // 获取当前列表项对应的数据源 EmployeeData employeeData = getItem(position); // 先获取所有需要操作的控件 TextView name = convertView.findViewById(R.id.name); TextView arrived = convertView.findViewById(R.id.arrived); TextView otp = convertView.findViewById(R.id.otp); View gender = convertView.findViewById(R.id.gender); TextView pickDropTime = convertView.findViewById(R.id.pickDropTime); View call = convertView.findViewById(R.id.call); // 1. 重置所有控件到默认状态(与布局初始状态或非特殊列表项的预期状态一致) name.setText(employeeData.getName()); arrived.setText(employeeData.getArrivedText()); arrived.setBackgroundTintList(context.getResources().getColorStateList(R.color.default_arrived_bg)); otp.setText(employeeData.getOtp()); otp.setBackgroundTintList(context.getResources().getColorStateList(R.color.default_otp_bg)); gender.setVisibility(View.VISIBLE); pickDropTime.setText(employeeData.getPickDropTime()); call.setVisibility(View.VISIBLE); // 2. 针对特殊条件修改控件状态 if(employeeData.getRideId().equals("-1") && position != 0 && cabDetails.getRideType().equals("0")) { name.setText("Office"); arrived.setText(""); arrived.setBackgroundTintList(context.getResources().getColorStateList(R.color.colorWhite)); otp.setText(""); otp.setBackgroundTintList(context.getResources().getColorStateList(R.color.colorWhite)); gender.setVisibility(View.INVISIBLE); pickDropTime.setText(new DateTime().Convert24To12Format(cabDetails.getLoginLogoutDateTime().split(" ")[1])); call.setVisibility(View.INVISIBLE); } return convertView; }
额外性能优化:ViewHolder模式
为避免每次getView都重复调用findViewById,可以用ViewHolder缓存控件引用,进一步提升滚动流畅度:
// 定义ViewHolder类缓存控件引用 static class ViewHolder { TextView name; TextView arrived; TextView otp; View gender; TextView pickDropTime; View call; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false); holder = new ViewHolder(); holder.name = convertView.findViewById(R.id.name); holder.arrived = convertView.findViewById(R.id.arrived); holder.otp = convertView.findViewById(R.id.otp); holder.gender = convertView.findViewById(R.id.gender); holder.pickDropTime = convertView.findViewById(R.id.pickDropTime); holder.call = convertView.findViewById(R.id.call); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } EmployeeData employeeData = getItem(position); // 重置默认状态 holder.name.setText(employeeData.getName()); holder.arrived.setText(employeeData.getArrivedText()); holder.arrived.setBackgroundTintList(context.getResources().getColorStateList(R.color.default_arrived_bg)); holder.otp.setText(employeeData.getOtp()); holder.otp.setBackgroundTintList(context.getResources().getColorStateList(R.color.default_otp_bg)); holder.gender.setVisibility(View.VISIBLE); holder.pickDropTime.setText(employeeData.getPickDropTime()); holder.call.setVisibility(View.VISIBLE); // 特殊条件处理 if(employeeData.getRideId().equals("-1") && position != 0 && cabDetails.getRideType().equals("0")) { holder.name.setText("Office"); holder.arrived.setText(""); holder.arrived.setBackgroundTintList(context.getResources().getColorStateList(R.color.colorWhite)); holder.otp.setText(""); holder.otp.setBackgroundTintList(context.getResources().getColorStateList(R.color.colorWhite)); holder.gender.setVisibility(View.INVISIBLE); holder.pickDropTime.setText(new DateTime().Convert24To12Format(cabDetails.getLoginLogoutDateTime().split(" ")[1])); holder.call.setVisibility(View.INVISIBLE); } return convertView; }
内容的提问来源于stack exchange,提问作者Prajjwal Srivastav
相关产品推荐
相关产品推荐

