滚动Activity加载90张图片内存溢出,求按需加载实现方案
解决滚动加载90张图片崩溃的问题
首先,你的崩溃大概率是内存溢出(OutOfMemoryError)——直接把90张Drawable资源一次性加载到内存,哪怕GridView已经在复用View,图片占用的内存依然会累积导致崩溃。下面是分步解决方案:
1. 修复Adapter里的内存泄漏问题
你的GridAdapter里直接用Heroes.this启动Activity,会让Adapter持有Activity的强引用,导致内存泄漏。改成用传入的上下文:
convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent toAtt = new Intent(myLayout, HeroAttributes.class); toAtt.putExtra("item", heroes.get(position)); // 适配不同上下文场景 if (myLayout instanceof Activity) { ((Activity) myLayout).startActivity(toAtt); } else { toAtt.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); myLayout.startActivity(toAtt); } } });
2. 优化图片加载(核心解决OOM)
直接用setImageResource()会解码整张原图到内存,哪怕图片只显示在小格子里,这是内存溢出的元凶。推荐两种优化方式:
方式一:用成熟图片加载库(最省心)
比如Glide,自动处理压缩、缓存和内存管理:
- 先在
build.gradle添加依赖:
implementation 'com.github.bumptech.glide:glide:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
- 替换Adapter里的图片加载代码:
Glide.with(myLayout) .load(heroes.get(position).getButton()) .centerCrop() .into(imageView);
方式二:手动实现图片压缩(基础版)
如果不想用第三方库,可手动压缩图片到格子大小:
// 添加压缩工具方法 private Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); } private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
然后在getView()里使用:
// 获取GridView单格宽度(按4列计算) int gridItemWidth = parent.getWidth() / 4; Bitmap compressedBitmap = decodeSampledBitmapFromResource( myLayout.getResources(), heroes.get(position).getButton(), gridItemWidth, gridItemWidth ); imageView.setImageBitmap(compressedBitmap);
3. 优化对象初始化(可选)
你现在一次性创建90个Hero对象,虽然内存占用不大,但可以改成按需创建减少初始内存负载:
- 去掉Activity里的
CreateList()方法,直接把names和images数组传给Adapter - 修改Adapter构造方法与相关逻辑:
private String[] names; private Integer[] images; public GridAdapter(Context context, String[] names, Integer[] images) { this.myLayout = context; this.names = names; this.images = images; this.filterHeroes = new ArrayList<>(); // 初始化过滤列表 for (int i = 0; i < names.length; i++) { filterHeroes.add(new Hero(images[i], names[i])); } } @Override public int getCount() { return heroes.size(); } @Override public Object getItem(int position) { return heroes.get(position); }
这样初始时不会一次性创建所有Hero对象,进一步降低内存占用。
4. 保留现有View复用逻辑
你当前getView()里的convertView == null判断是正确的,它会自动复用滑出屏幕的View,避免重复创建View对象,继续保持即可。
总结:崩溃的核心是图片加载导致的内存溢出,优先用Glide这类库解决图片问题,再修复内存泄漏,就能流畅滚动90张图片了。
内容的提问来源于stack exchange,提问作者Nas Gue
相关产品推荐
相关产品推荐

