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

Android天气应用GroundOverlay内存过高引发OOM问题求助

解决Android天气应用动画导致的OOM问题

哥们,你的这个OOM问题我太熟了——虽然PNG文件看着是KB级,但Bitmap解码后是按像素计算内存的(比如ARGB_8888格式下,1080×1920的Bitmap就占约8MB),要是一次性把所有帧的Bitmap都存进HashMap,内存肯定扛不住。给你几个实用的解决方案,组合起来用应该能彻底解决问题:

1. 按需加载+及时回收Bitmap,不要全量缓存

不要一次性加载所有帧并永久存在HashMap里,只保留当前显示帧和前后1-2帧的资源,其他帧用完就立刻回收Bitmap并移除对应的GroundOverlay,释放内存。

你可以先把HashMap的存储对象改成包含Bitmap和GroundOverlay的自定义类,方便后续统一管理:

// 自定义类,封装Bitmap和对应的GroundOverlay
static class WeatherOverlayHolder {
    Bitmap bitmap;
    GroundOverlay overlay;
}

然后在切换动画帧的逻辑里,主动回收上一帧的资源:

// 假设currentTime是当前显示的帧时间,nextTime是要切换的目标帧时间
WeatherOverlayHolder currentHolder = groundOverlaysItemMap.get(currentTime);
if (currentHolder != null) {
    // 回收Bitmap
    if (currentHolder.bitmap != null && !currentHolder.bitmap.isRecycled()) {
        currentHolder.bitmap.recycle();
        currentHolder.bitmap = null;
    }
    // 移除地图上的Overlay
    currentHolder.overlay.remove();
    // 从HashMap中删除,避免内存泄漏
    groundOverlaysItemMap.remove(currentTime);
}

// 加载并显示下一帧...

2. 让Glide加载缩小后的Bitmap,减少单帧内存占用

根据GoogleMap的实际显示区域,计算需要的Bitmap尺寸,让Glide加载时直接缩小图片——毕竟地图上显示的区域有限,没必要用全分辨率的图。

代码示例:

// 获取当前地图可见区域的像素尺寸
Projection projection = mMap.getProjection();
VisibleRegion visibleRegion = projection.getVisibleRegion();
Point northeastPoint = projection.toScreenLocation(visibleRegion.latLngBounds.northeast);
Point southwestPoint = projection.toScreenLocation(visibleRegion.latLngBounds.southwest);
int targetWidth = northeastPoint.x - southwestPoint.x;
int targetHeight = southwestPoint.y - northeastPoint.y; // 注意Android坐标系y轴方向

// 用Glide加载时指定目标尺寸,避免加载过大的Bitmap
Glide.with(this)
     .asBitmap()
     .load(yourImageUrl)
     .override(targetWidth, targetHeight) // 可乘以1.5f保证清晰度,比如(targetWidth*1.5f).intValue()
     .into(new CustomTarget<Bitmap>() {
         @Override
         public void onResourceReady(@NonNull Bitmap bitmap, @Nullable Transition<? super Bitmap> transition) {
             Log.i("Weather", "优化后Bitmap大小: " + bitmap.getByteCount());
             // 后续创建GroundOverlay并存入HashMap
             WeatherOverlayHolder holder = new WeatherOverlayHolder();
             holder.bitmap = bitmap;
             holder.overlay = mMap.addGroundOverlay(overlayOptions);
             groundOverlaysItemMap.put(mTime, holder);
         }

         @Override
         public void onLoadCleared(@Nullable Drawable placeholder) {}
     });

3. 使用低内存的Bitmap解码格式

如果你的天气图标不需要全透明通道(或者可以接受半透明损失),可以把Bitmap的解码格式从默认的ARGB_8888改成RGB_565,这样每个像素只占2字节,内存直接减半。

代码示例:

Glide.with(this)
     .asBitmap()
     .load(yourImageUrl)
     .setBitmapDecodeFormat(BitmapDecodeFormat.RGB_565) // 设置低内存格式
     .override(targetWidth, targetHeight)
     .into(new CustomTarget<Bitmap>() {
         // ...
     });

4. 用LruCache限制缓存大小

自定义LruCache来管理Bitmap缓存,设置最大缓存容量(比如应用可用内存的1/8),这样超过容量的Bitmap会被自动回收,避免内存溢出。

代码示例:

// 计算最大缓存大小:应用最大可用内存的1/8,单位KB
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;

LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        // 返回Bitmap的大小,单位KB
        return bitmap.getByteCount() / 1024;
    }
};

// 加载Bitmap时先从缓存取,没有再从网络加载
Bitmap cachedBitmap = bitmapCache.get(yourImageUrl);
if (cachedBitmap != null) {
    // 使用缓存的Bitmap创建Overlay
} else {
    Glide.with(this)
         .asBitmap()
         .load(yourImageUrl)
         .into(new CustomTarget<Bitmap>() {
             @Override
             public void onResourceReady(@NonNull Bitmap bitmap, @Nullable Transition<? super Bitmap> transition) {
                 bitmapCache.put(yourImageUrl, bitmap);
                 // 后续处理...
             }

             @Override
             public void onLoadCleared(@Nullable Drawable placeholder) {}
         });
}

额外注意事项

  • 在Activity/Fragment的onDestroy()方法里,一定要清空groundOverlaysItemMap,并回收所有剩余的Bitmap,避免内存泄漏。
  • 可以结合Glide的内存缓存策略,比如禁用Glide的内存缓存(如果自己用LruCache管理的话),避免重复缓存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:53:12