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

Android使用Picasso加载网络图片到ListView时程序崩溃问题

问题核心原因
  • 你将lv.setAdapter(adapter)写在了遍历JSON数组的for循环内部,每添加一条数据就会触发ListView全量重绘,性能极差且会导致视图状态混乱。
  • 你在Activity中直接调用findViewById(R.id.imageViewLogoNews)查找列表项内的ImageView,这个方法只会找到当前布局树中第一个匹配ID的控件,并非ListView每一行对应的图片控件,此时列表项可能还未完成渲染,直接操作就会触发空指针或视图状态不匹配的崩溃。
  • 原生SimpleAdapter默认仅支持绑定本地drawable资源、资源ID类型的图片,无法直接识别网络URL字符串并自动加载图片,你把URL传入默认绑定逻辑必然会触发类型匹配错误。
  • 你之前单独给非列表的普通ImageView用Picasso加载正常,是因为那个ImageView直接属于Activity布局层级,不属于ListView动态渲染的子项,不存在视图复用和查找错位的问题。
修复方案
  1. 把适配器设置逻辑移出for循环,等所有接口数据全部解析添加到列表集合后,再一次性绑定适配器。
  2. 废弃原生SimpleAdapter,自定义继承自BaseAdapter的列表适配器,通过ViewHolder模式做列表项视图复用,在适配器的getView方法中绑定每一行的数据、加载对应图片。
  3. 不要在Activity层直接查找列表项内部的控件,所有列表项的控件查找、数据绑定逻辑都放到自定义适配器内部完成。

核心实现代码

自定义列表适配器

public class AnnonceAdapter extends BaseAdapter {
    private Context mContext;
    private ArrayList<HashMap<String, String>> mDataList;

    public AnnonceAdapter(Context context, ArrayList<HashMap<String, String>> dataList) {
        this.mContext = context;
        this.mDataList = dataList;
    }

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

    @Override
    public Object getItem(int position) {
        return mDataList.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        // 复用列表项视图,避免反复inflate造成性能损耗
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.listview_layout, parent, false);
            holder = new ViewHolder();
            holder.titreTv = convertView.findViewById(R.id.titre_de);
            holder.descTv = convertView.findViewById(R.id.description_de);
            holder.refTv = convertView.findViewById(R.id.reference);
            holder.logoIv = convertView.findViewById(R.id.imageViewLogoNews);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        // 绑定当前行对应的数据
        HashMap<String, String> itemData = mDataList.get(position);
        holder.titreTv.setText(itemData.get(titret));
        holder.descTv.setText(itemData.get(descriptionet));
        holder.refTv.setText(itemData.get(reft));
        // 加载当前行对应网络图片
        String imgUrl = itemData.get(url_imaget);
        Picasso.get()
                .load(imgUrl)
                .placeholder(R.mipmap.ic_launcher) // 可替换为你自己的加载占位图
                .error(R.mipmap.ic_launcher) // 可替换为你自己的加载失败提示图
                .into(holder.logoIv);

        return convertView;
    }

    // ViewHolder缓存控件实例,避免反复findViewById
    static class ViewHolder {
        TextView titreTv;
        TextView descTv;
        TextView refTv;
        ImageView logoIv;
    }
}

修改后的接口回调逻辑

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
    if (response.isSuccessful()) {
        myResponse = response.body().string();
        Annonces.this.runOnUiThread(() -> {
            try {
                JSONObject reader = new JSONObject(myResponse);
                JSONArray eglises = reader.getJSONArray("Annonces_adv");
                arrayList.clear();

                for (int i = 0; i < eglises.length(); i++) {
                    JSONObject eglise = eglises.getJSONObject(i);
                    String titre = eglise.getString(titret);
                    String description = eglise.getString(descriptionet);
                    int ref = Integer.parseInt(eglise.getString(reft));
                    String url_image = eglise.getString(imaget);

                    HashMap<String, String> data = new HashMap<>();
                    data.put(titret, titre);
                    data.put(descriptionet, description);
                    data.put(reft, String.valueOf(ref));
                    data.put(url_imaget, url_image);
                    arrayList.add(data);
                }
                // 所有数据解析完成后再绑定适配器
                AnnonceAdapter adapter = new AnnonceAdapter(Annonces.this, arrayList);
                lv.setAdapter(adapter);

            } catch (JSONException e) {
                e.printStackTrace();
            }
        });
    }
}

额外检查项:

  • 确认AndroidManifest.xml中已经声明网络权限:<uses-permission android:name="android.permission.INTERNET" />
  • 如果你的图片URL是HTTP而非HTTPS,Android 9及以上系统需要配置网络安全策略允许明文流量,否则会被系统拦截导致图片加载失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:21:37