You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android自定义Adapter复用View时图片频繁切换问题求助

解决ListView适配器复用后图片错乱+滚动卡顿问题

问题拆解

你现在碰到两个头疼的问题:没启用ViewHolder时列表滚动卡顿,启用后又出现头像快速切换错乱的情况。咱们一步步来搞定它们:

问题根源分析

  1. 滚动卡顿原因:没启用ViewHolder时,每次getView都会重新解析布局、查找控件,这是非常消耗资源的操作,自然导致滚动不流畅。
  2. 图片错乱原因:核心是异步加载和View复用的冲突。滚动列表时,旧的列表项View会被回收给新的位置,但之前发起的Firebase URL请求、Glide图片加载都是异步操作,旧请求完成后会把错误的图片加载到已经复用的View上,就出现了你看到的图片跳来跳去的情况。

修复方案

下面是优化后的完整代码,关键改动我都标出来了:

import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageException;
import com.google.firebase.storage.StorageReference;
import java.util.List;

public class CustomAdapter extends BaseAdapter {
    Context context;
    List<RowItem> rowItems;

    CustomAdapter(Context context, List<RowItem> rowItems) {
        this.context = context;
        this.rowItems = rowItems;
    }

    @Override
    public int getCount() {
        return rowItems.size();
    }

    // 优化:原来返回position,现在直接返回对应RowItem,逻辑更合理
    @Override
    public RowItem getItem(int position) {
        return rowItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    /* private view holder class */
    private class ViewHolder {
        ImageView profile_pic;
        TextView member_name;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        final RowItem row_pos = getItem(position);
        
        // 1. 正确启用ViewHolder复用(恢复你注释的核心代码)
        if (convertView == null) {
            LayoutInflater mInflater = LayoutInflater.from(context);
            convertView = mInflater.inflate(R.layout.list_item, parent, false);
            holder = new ViewHolder();
            holder.member_name = convertView.findViewById(R.id.member_name);
            holder.profile_pic = convertView.findViewById(R.id.profile_pic);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        // 设置名称
        holder.member_name.setText(row_pos.getName());

        // 2. 关键修复:加载新图片前清除旧请求,避免旧请求覆盖新内容
        Glide.with(context).clear(holder.profile_pic);
        // 3. 设置默认占位图,加载过程中显示,减少视觉错乱
        holder.profile_pic.setImageResource(R.drawable.user);

        // 获取Firebase Storage引用
        StorageReference storageReference = FirebaseStorage.getInstance().getReference()
                .child(row_pos.getFirebaseUserUid() + ".jpg");

        storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
            @Override
            public void onSuccess(Uri uri) {
                // 加载网络图片
                Glide.with(context)
                        .load(uri)
                        .apply(RequestOptions.circleCropTransform())
                        .into(holder.profile_pic);
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception exception) {
                int errorCode = ((StorageException) exception).getErrorCode();
                if (errorCode == StorageException.ERROR_OBJECT_NOT_FOUND) {
                    // 图片不存在时显示默认图
                    holder.profile_pic.setImageResource(R.drawable.user);
                }
            }
        });
        return convertView;
    }
}

额外性能优化建议

  • 缓存Firebase下载URL:每次调用getDownloadUrl()都会发起网络请求,你可以把获取到的URL存在RowItem对象里,下次直接使用,避免重复请求。比如给RowItem添加private String avatarUrl;字段,成功获取URL后赋值,后续直接用这个URL加载图片。
  • 迁移到RecyclerView:ListView属于较旧的组件,RecyclerView的ViewHolder机制更完善,性能更好,还支持更多布局类型,是当前Android列表组件的首选,建议后续考虑迁移。

内容的提问来源于stack exchange,提问作者ITG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:38:30