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

Navigation Drawer Header 背景图片内存占用过高问题如何解决?

内存异常上涨的根本原因

你看到的32KB是JPEG的压缩存储体积,和加载到内存后的实际占用是两个完全不同的概念:

  • Android加载图片资源时会先把压缩格式的JPEG解码为原始位图,默认使用ARGB_8888配置,每个像素占用4字节。如果不对图片做任何压缩处理,1600*900分辨率的位图本身就要占用 1600 * 900 * 4 = 5.76MB 内存
  • 更核心的原因是资源目录适配问题:如果你的图片放在了低DPI的资源文件夹(比如默认的drawable文件夹等价于drawable-mdpi),在高DPI设备上系统会自动按DPI比例缩放位图来适配显示,比如在xxhdpi设备上会放大3倍,缩放后的分辨率变成4800*2700,仅这一张图就要占用 4800 * 2700 * 4 = 51.84MB 内存,这就是你启动后内存直接飙升的核心原因。

优化方案

    1. 正确放置图片资源
      不要把图片直接放在根drawable目录下,根据你图片的目标DPI放到对应文件夹,比如针对主流xxhdpi设备就放到drawable-xxhdpi文件夹;如果希望图片不被系统自动缩放,直接放到drawable-nodpi目录即可。
    1. 调整解码配置降低内存占用
      这张背景图不需要透明通道,可以改用RGB_565解码配置,每个像素仅占用2字节,内存占用直接减少一半。如果是xml设置背景,可以在res/drawable下新建一个xml drawable指定配置:
    <?xml version="1.0" encoding="utf-8"?>
    <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
      android:src="@drawable/navigation_header_bg"
      android:config="RGB_565" />
    
    然后把布局的background改成指向这个xml drawable即可。
    1. 按实际显示尺寸采样加载
      你的导航头高度只有200dp,实际显示高度远低于原图900px的高度,可以通过采样压缩后再加载。更推荐直接用Glide来加载背景,自动完成采样适配:
    // Kotlin代码示例,在NavigationView初始化后调用
    val headerView = navigationView.getHeaderView(0)
    // 先给你的根布局加id为header_root
    val headerLayout = headerView.findViewById<ConstraintLayout>(R.id.header_root) 
    Glide.with(this)
      .asBitmap()
      .load(R.drawable.navigation_header_bg)
      .into(object : CustomTarget<Bitmap>() {
          override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
              headerLayout.background = BitmapDrawable(resources, resource)
          }
          override fun onLoadCleared(placeholder: Drawable?) {}
      })
    
    1. 配套优化RecyclerView图片加载
      针对列表滑动内存上涨的问题,给Glide加载加上固定尺寸限制,避免加载过大的图片到内存:
    // Adapter里加载图片的代码示例
    Glide.with(context)
      .load(图片路径)
      .override(目标ImageView的宽高,比如400.dpToPx())
      .centerCrop()
      .into(imageView)
    
    同时可以给RecyclerView添加滑动监听,滑动时暂停Glide加载,减少卡顿和内存波动:
    recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            if (Math.abs(dy) > 10) {
                Glide.with(context).pauseRequests()
            } else {
                Glide.with(context).resumeRequests()
            }
        }
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                Glide.with(context).resumeRequests()
            }
        }
    })
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 10:57:01