如何在RecyclerView中加载URL图片并解决Network Thread异常问题
问题原因
你遇到的Network Thread异常是因为Android系统禁止在**主线程(UI线程)**执行网络请求,onBindViewHolder方法运行在主线程,你直接在其中发起HttpURLConnection请求自然会触发报错。除此之外你的代码还存在图片列表下标越界、无缓存、列表复用错位等潜在问题。
最优方案:使用成熟图片加载框架
强烈建议直接使用第三方图片加载库,一行代码即可完成需求,库会自动处理线程调度、内存/磁盘缓存、列表滑动复用错位、OOM规避、加载状态占位等问题,不需要你手动写复杂的网络加载逻辑。
以Glide为例,替换原有加载图片的全部代码即可:
// 注意你原有代码getImages().get(position)是错误写法:每个专辑的图片列表一般只有3个不同尺寸,列表position超过3就会越界,应取对应尺寸的下标,比如取第0个大图或者第2个缩略图 String imageUrl = model.getTrack().getAlbum().getImages().get(0).getUrl(); Glide.with(context) .load(imageUrl) // 可选:设置加载中的占位图 .placeholder(R.drawable.placeholder_cover) // 可选:设置加载失败的占位图 .error(R.drawable.error_cover) .into(holder.songCover);
原有代码修复方案
如果你坚持要自己实现图片加载逻辑,需要把网络请求放到子线程执行,完成后切回主线程设置图片,同时要处理列表复用错位问题:
@Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { ItemPayload model = list.get(position); Log.d("aaa",model.getTrack().getName().toString()); // 先给ImageView设置tag,防止复用错位 String image = model.getTrack().getAlbum().getImages().get(0).getUrl(); holder.songCover.setTag(image); // 子线程加载图片 new Thread(() -> { Bitmap mIcon_val = null; try { URL newurl = new URL(image); HttpURLConnection conn= (HttpURLConnection)newurl.openConnection(); conn.setDoInput(true); conn.connect(); InputStream is = conn.getInputStream(); mIcon_val = BitmapFactory.decodeStream(is); } catch (IOException e) { e.printStackTrace(); } // 切回主线程设置图片 Bitmap finalMIcon_val = mIcon_val; ((Activity)context).runOnUiThread(() -> { // 比对tag,避免复用错位 if (holder.songCover.getTag().equals(image) && finalMIcon_val != null) { holder.songCover.setImageBitmap(finalMIcon_val); } }); }).start(); // 后续原有逻辑不变 holder.textSong.setText(model.getTrack().getName()); holder.textArtist.setText(model.getTrack().getArtists().get(0).getName()); holder.textTrack.setText(model.getTrack().getAlbum().getTotal_tracks().toString()); String url = model.getTrack().getExternal_urls().getSpotify(); holder.textSong.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent viewIntent = new Intent("android.intent.action.VIEW", Uri.parse(url)); viewIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(viewIntent); } }); }
注意:自行实现的方案仍缺少缓存、OOM处理、加载状态等能力,仅作为原理参考,生产环境优先使用成熟框架。
内容的提问来源于stack exchange,提问作者Aditya
相关产品推荐
相关产品推荐

