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

滚动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,自动处理压缩、缓存和内存管理:

  1. 先在build.gradle添加依赖:
implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
  1. 替换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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 22:42:45