
用了这么多年Android手头攒了几百个图标文件有从各类设计稿里切出来的PNG也有自己画的矢量图还有从第三方图标库下载的成套资源。很多开发者找我聊图标资源管理的问题通常都是聊到一半才发现大家真正头疼的不是缺一个图标而是图标一多就乱——命名不规范、密度适配漏掉、加载方式选错、包体积超标、换肤时图标跟着变色崩溃。这篇博文我想把这块的经验完整梳理一遍从选型到落地从静态资源到运行时加载尽量让每个环节都有可以直接照搬的做法。我先把话说在前面这篇文章的标题虽然叫矢量图标大全但你会发现我花了大量篇幅在讲PNG。这恰恰是实际项目里最真实的状态——矢量图标很香但不是万能的PNG很传统却依然是很多场景绕不开的选择。真正高效的做法是知道什么时候用哪种以及怎么把两者在工程里共存、管好、用好。接下来我就按这个思路展开前面几章会把原理和选型讲透中间几章是实打实的工程配置和代码细节最后专门用一章来复盘那些高频踩坑现场。1. 矢量优先还是PNG兜底先搞清两种格式在Android里的真实地位很多刚入行的朋友会有一个错觉Android从5.0开始支持VectorDrawable图标就应该全面改用矢量图PNG是老古董。这个想法我在不少项目里见到过但实际推进起来往往碰壁。先把两者的本质差异聊清楚你才知道什么场景下矢量优先成立什么场景下必须PNG兜底。矢量图在Android里对应的就是VectorDrawable本质是一段遵循SVG路径语法的XML描述。它的核心优势有两个一是适配不同屏幕密度不需要出多套图一套矢量描述任意缩放都保持清晰二是运行时可以动态改颜色同一份图标资源通过Tint就能输出多种颜色版本换肤也好、多主题也好都省事得多。但矢量图也有它绕不开的短板。第一VectorDrawable对路径复杂度敏感一个图标如果要几十上百个path节点首帧渲染和动画计算的开销会明显上升这在低端机上尤其明显第二不是所有视觉效果都能用路径描述比如带复杂渐变、阴影、噪点纹理的拟物图标硬转成矢量要么体积爆炸要么效果失真第三Android 5.0以下不支持原生的VectorDrawableAppCompat虽然提供了兼容方案但兼容包在inflate和绘制上也有额外开销且有些特性比如VectorDrawable的某些path动画在老版本上支持不完整。PNG在Android里就没什么花头它是标准的位图格式带alpha通道设计稿里怎么看到手机上就是什么样。代价也很直接要保证不同屏幕密度的显示效果就得按mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi各准备一套或者干脆用一套高分辨率硬撑后者在内存和包体积上都不划算。我个人的选型习惯是这样的App内部的UI图标比如工具栏、Tab栏、设置项图标、占位符号这类纯色系、结构简单的图标优先考虑矢量方案如果是市场运营位、品牌视觉图、插画、带质感的图标或者从设计侧拿到的就是多层渐变或复杂光效的稿子老老实实用PNG。还有一类情况也要注意第三方SDK通常只给你PNG资源接入支付、推送、地图这类SDK时小图标可能还好但带有品牌标识的图标几乎都是位图接收就好别想着自己转矢量。有不少同学问过我一个问题为什么我直接把一个几百KB的透明背景PNG放进drawable里界面就卡顿甚至OOM这里面有一个容易忽略的点PNG在Android里加载进内存是解压成ARGB位图的分辨率越大占的内存越高。一个512x512的png在内存里就是512乘512乘4字节差不多1MB如果这个图标被加载到多个页面或者被放进一个频繁操作的列表里内存问题很快就能感觉到。关于这一点后面运行时加载那一节我会展开讲。还有一点我需要特别提醒千万不要用一张24x24的小PNG去适配所有屏幕也别为了图省事只放一张超大PNG。前者在1080P以上的屏幕上会糊后者在低端机上内存吃不消。正确逻辑永远是密度适配或者密度自适配矢量天然自适配。这里可以给出一个简单的对照表帮助团队在评审图标资源格式时快速达成一致场景推荐格式原因纯色/双色简单UI图标矢量Drawable体积小、支持Tint换色、任意密度清晰渐变、阴影、纹理丰富的图标PNG按密度多套矢量难以描述复杂视觉效果启动图标/通知图标PNG必要时WebP系统级要求位图且对兼容性要求高运营插画/BannerPNG/WebP通常为合成图片非单一图标需要动画的图标路径动画矢量Drawable支持路径动画位图做动画代价大第三方SDK内置图标跟随SDK方案保持SDK内部一致性避免改造风险看完这个表你就明白所谓矢量图标大全真正的重点其实是矢量与位图的资源管理策略而不是简单地把所有图标都变成矢量。接下来我把工程里的具体操作拆开讲。2. 图标资源的两种主流生产方式矢量绘制与PNG切图的关键细节确定了格式选型之后紧接着的问题就是图从哪来。这里我分两条线讲一是直接用Android Studio内置的Vector Asset工具生成矢量图标二是从设计稿切出合格的PNG图标。这两条线我都有踩坑经历不信你看下去。2.1 Android Studio的Vector Asset内置图标库与自定义SVG的导入验证Android Studio的Vector Asset算是生成矢量图标最快的一条路。右键res目录New - Vector Asset弹出的窗口里可以选内置的Material Icon也可以指向本地SVG文件导入。这里有一个许多人不注意的细节Asset Studio在导入SVG时并不保证100%转换成功尤其遇到路径里有特殊操作、复杂的渐变填充、mask或filter效果时要么转换报错要么生成的VectorDrawable路径异常。所以导入完成后不要急着用先点开XML看一眼再放到页面里跑一下确认显示效果。我自己的习惯是优先使用Material官方图标库因为那是Google维护的路径质量有保障。但项目用到比较特定的业务图标时就得找设计师要SVG。设计侧交付SVG时有几个约束要提前说清楚画布尺寸建议基于24x24或48x48的标准网格路径尽量用纯色填充不要用渐变因为VectorDrawable虽然支持渐变但兼容性和性能都不理想不要嵌套太多图层导出前最好把路径合并成单一复合路径。点击导入后AS会生成一个XML文件默认放在drawable目录下。这个XML打开后是一个vector节点里面有viewportWidth、viewportHeight、width、height以及path的pathData。有一点要特别注意width和height是最终显示尺寸如果你同时在不同密度设备上使用建议把这两个值写成具体dp而不是wrap_content式的写法避免在个别场景下被拉伸变形。2.2 手动转换SVG为VectorDrawable写PathData时的坐标系逻辑如果你拿到的SVG文件结构比较复杂或者转出来的XML路径有明显问题我建议你学会手动处理几个基础动作调整viewportWidth和viewportHeight检查pathData是否闭合把不必要的fillColor集中到一个path上。手动改PathData并不需要你完整掌握SVG语法但需要对坐标系有直觉。VectorDrawable的viewPort是一个抽象的逻辑坐标系最终显示大小由width和height决定。这个设计其实很像svg里的viewBox。pathData里常见的MmoveTo、LlineTo、C贝塞尔曲线、Z闭合都是标准SVG命令。当你手动从SVG的path中复制pathData时注意除去SVG里关于transform或fill的干扰信息。说白了核心路径保存下来就行。我见过不少团队为了一个简单箭头图标从iconfont网站复制了一段SVG代码结果导进去显示成一团黑。原因通常是fill-rule不对或者SVG里存在多个非零填充的子路径交叉。遇到这种情况建议在iconfont里先把图标改成单色然后导出再导入AS。如果还是不行就用Sketch或Figma打开原文件把图标转为Outline再导出SVG路径会干净很多。2.3 从设计稿切PNGpng与jpg的本源区别和透明背景处理从PS或Figma切图时PNG和JPG的选择通常不是看哪个格式更有高级感而是看透明度需求。PNG支持8bit透明通道JPG不支持JPG用有损压缩适合照片类图标这类边缘清晰、需要透明底或纯色块的内容一律用PNG或者现在更推荐的WebP。具体到切图操作中最大的坑有两个一个是边缘杂边。设计师在深色底上切出来的白色图标直接放到浅色界面上边缘会出现一圈灰色晕边。解决方法是让设计师在透明底上导出切图前把图层的羽化和阴影处理干净。另一个是尺寸锚点错误。AS里的drawable目录有很多种你得按mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi分别放入对应尺寸的PNG比例大体为密度缩放比例以mdpi为基准举例24dp图标对应像素mdpi1x24x24hdpi1.5x36x36xhdpi2x48x48xxhdpi3x72x72xxxhdpi4x96x96很多新手会把同一个512x512的PNG一股脑塞进所有drawable文件夹这实际上是错误的等于放弃了密度适配。Android系统会根据设备dpi选择对应密度文件夹里的资源如果你只在xxhdpi下放了图在mdpi设备上它会尝试缩放但效果不如在每个密度下给对应尺寸的资源来得好。切图时我还会特别留意命名规范。Android的资源名只能包含小写字母、数字和下划线不能用大写字母也不推荐用中文。一个比较通用的命名格式是模块_类型_描述比如ic_home_selector.xml、bg_login_pressed.9.png。如果项目里图标一多一个清晰统一的命名规则就是索引效率的保证别等到三个月后自己都认不出那是哪个界面的图标。3. 工程落地Drawable资源与Mipmap资源的目录规划、命名规范与lint校验资源管理做到工程层面其实就是目录规划、命名规则和构建约束这三件事。很多项目早期不重视图标越堆越多最后整个drawable目录几千个文件找一张图比重新画一张还费时间。3.1 mipmap与drawable千万别乱放启动图标和其他图标的物理隔离系统资源目录里drawable和mipmap经常被混用。官方建议是只有App的启动图标ic_launcher放在mipmap目录其余图像资源全部放drawable。为什么mipmap目录在设计上是给系统保留的部分设备在生成自适应图标时会特别处理mipmap里的资源如果你把其他普通图标也放进来不仅没有好处还可能因为不同密度文件夹下的同名资源引起混淆。实际项目里我见过把某张运营图放到mipmap-xxxhdpi里导致其他密度下加载失败的情况原因就是找不到对应密度的资源。如果你同时在使用自适应图标Adaptive Iconmipmap-anydpi-v26目录下还会有一份XML的adaptive-icon配置里面引用了前景和背景。这里要提醒的是老设备上Adaptive Icon不生效系统会回退到mipmap各密度下的传统PNG图标因此框架一定要保留好不同密度的传统图标不能贪图省事只放一张高分辨率图。3.2 统一命名规范与目录分层如何让图标按业务模块清晰检索命名这件事团队里一定要有统一的约定。我自己比较推荐的方式是模块前缀login、home、profile、checkout等业务模块名作为前缀如ic_login_wechat文件类型前缀ic_表示普通图标bg_表示背景图selector_表示状态选择器anim_表示帧动画资源状态后缀_normal、_pressed、_selected、_disabled结合selector使用是否9图文件名以.9.png结尾比如bg_login_btn.9.png这套规范的好处是任何人从文件名就能知道这图放哪、什么状态、大概长什么样。配合AS里File - Search或者全局搜索文件名效率提升非常明显。说真的我接手过命名全是xx.png、photo1.png、img2.png的项目每次改样式都要把所有图片翻一遍那种痛苦你应该能理解。除了命名目录分层也可以配合业务模块做。比如res/drawable/login/、res/drawable/home/这类Android Gradle Plugin从AGP 7.0开始支持在drawable下用子目录方式管理资源官方术语叫资源目录的限定符与子目录功能准确说AGP支持src/main/res/drawable下的任意子目录组织构建时会自动把它们合入同一R类。这个能力很好用强烈建议开启。3.3 资源引用与lint强约束R文件规范、混淆排查与无用资源检测Android的R文件是资源引用的总入口只要你正确引用IDE在编译阶段就能帮你检查资源是否存在。但有些情况会让资源引用变得隐蔽常见的是在代码里通过字符串拼接资源名再用getResources().getIdentifier()动态获取比如动态主题换肤这类用法build是查不出来的运行时一旦资源名对不上就直接崩掉或返回0。关于无用资源清理AS自带的Lint功能非常实用。Analyze - Run Inspection by Name输入Unused resources它能找出工程内没有被XML或Java/Kotlin引用的资源。需要注意的是如果你使用了动态获取资源的逻辑Lint可能误报这时候可以给特定资源加tools:keep或在res/raw下维护一份白名单。但总体上这条检查值得每次发版前跑一遍能清掉不少历史遗留的死资源。这里还要提一个构建配置在app/build.gradle里开启资源压缩。AGP的shrinkResources需要配合minifyEnabled使用开启后构建时会删除未被引用的资源。对一张PNG都不舍得删的团队来说这个开关能帮你自动减肥但要小心代码里通过getIdentifier()动态引用的资源需要配置res/raw/keep.xml来保住它们。4. 包体积与内存双优化从PNG到WebP从矢量资源到主题化的进阶玩法图标资源虽然单个体积不大但架不住数量多。一个中大型App资源目录下几百张PNG是常态全部加起来可能占APK好几MB。以我经历过的项目来看做完下面几项优化APK体积瘦身5%-10%是很常见的结果。4.1 Android Studio一键转换PNG到WebP兼容性门槛与质量参数Android Studio自带PNG转WebP的功能。在drawable目录下选中PNG文件右键Convert to WebP会弹出对话框让你选择质量参数和兼容性范围。现在普遍建议直接使用WebP因为它同时支持有损和无损压缩又支持alpha通道而且Android 4.0以后就默认支持WebP4.2.1以后支持带透明通道的WebP实际兼容性门槛已经很低了。我实测过一组50张左右的UI图标从PNG转WebP无损模式体积平均下降30%-50%切到有损模式质量85体积下降70%以上且肉眼几乎无差别。但有一点要提醒有损WebP在纯色边缘和渐变过渡上低质量参数下可能会出现轻微色块条纹建议图标类资源用无损模式或90以上质量照片类运营图可以用80-85的有损模式。转完之后记得在真机上肉眼过一遍别只看预览图。4.2 VectorDrawable与iconfont字体图标的取舍再算一遍体积这笔账前面已经说过矢量图的小体积优势。一个典型的Material图标矢量XML大概1-3KB而对应的PNG五套密度加起来往往有20-50KB。如果你有100个纯色UI图标全部换成矢量光是资源体积就能减少好几MB。这笔账怎么算都不亏。比矢量XML更极端的是iconfont方案也就是把几十上百个纯色图标合成一个字体文件通过TextView或ImageView配合自定义字体来显示。字体文件可能也就几十KB到一两百KB比单个矢量XML加起来更小。但iconfont方案有两个麻烦一是不方便在Android Studio的布局预览里直接查看二是换肤和着色要靠代码指定颜色出问题排查略麻烦。我的建议是如果项目里图标系统已经比较成熟可以继续用从零开始的话优先矢量XML方案它更贴合Android生态IDE支持也更好。4.3 drawable的Tint与Vector的color资源引用一套图多处用的关键矢量图还有一个隐藏技能通过app:tint给同一个drawable换颜色。比如你有一个黑色的返回箭头现在需要白色版本不需要再导一张白色PNG直接用ImageView android:layout_width24dp android:layout_height24dp android:srcdrawable/ic_arrow_back android:tintcolor/white /如果你用的是VectorDrawable还可以更彻底一点在XML内部把fillColor直接引用为color/icon_color这种主题属性这样当全局换肤时同一个矢量图标的所有实例都会自动跟随变化。这种方式在设计多套主题的App时非常省事不用为每套主题维护一套PNG。需要注意android:tint在API 21之前需要配合AppCompat的app:tint使用如果你要兼容老设备建议统一用app:tint并确保ImageView来自AppCompat库。我踩过一个坑在API 19的测试机上直接用android:tint不生效图标还是原来的黑颜色排查半天发现是兼容写法的问题。4.4 进阶Selector、LayerDrawable与AnimatedVectorDrawable把静态资源做活资源管理做到一定程度就要考虑一个图标当多个用。StateListDrawableselector可以根据控件的pressed、selected、enabled等状态切换不同图标或颜色LayerDrawable可以把多个drawable图层叠加成一个AnimatedVectorDrawable则通过属性动画控制矢量路径的变化实现开机动画、下载进度图标等效果。Selector最典型的应用是Tab栏图标选中态和未选中态各一张图用selector组织起来代码里一行设置搞定。selector xmlns:androidhttp://schemas.android.com/apk/res/android item android:state_selectedtrue android:drawabledrawable/ic_home_selected / item android:drawabledrawable/ic_home_normal / /selectorLayerDrawable适合做角标、数字徽标等叠加效果比如消息图标的右上角带一个红色数字点。AnimatedVectorDrawable相对复杂我建议项目本身已经有矢量路径基础再看它的动画文件里会涉及objectAnimator和路径插值器调试成本不低使用时要有心理准备。5. 运行时加载与动态主题Drawable缓存、OOM防护与资源动态匹配的实战经验静态资源管好了运行时加载就是另一层考验。很多崩溃和内存问题都发生在图标加载这个环节因为和文字、布局相比图片的加载链路更长涉及的缓存与解码也更容易出幺蛾子。5.1 图片加载框架选型Coil、Glide还是裸加载现在开发App几乎没有理由用裸的BitmapFactory.decodeResource去加载PNG除非你处理的是一两张用户自定义图片。项目里统一用图片加载库一方面是因为库内置了内存缓存、磁盘缓存和采样压缩另一方面是因为Coil和Glide都支持直接加载资源ID并且做了异步处理不会在UI线程解码导致卡顿。Coil基于Kotlin协程API更现代对VectorDrawable的支持也友好Glide历史更久生态成熟文档和案例更多。从资源加载角度两者的差别不大。如果你项目里大量使用矢量图标我更推荐Coil或者Glide都行但一定要留意库对VectorDrawable的处理——某些老旧版本在加载矢量Drawable时可能产生单帧动画的副作用需要特殊配置。5.2 Resource ID加载与Drawable缓存机制为何同一张图在不同页面表现不一致图片加载库内部都有三级缓存内存、磁盘、网络同一资源第一次加载后后续基本走内存缓存速度很快。这带来一个常见问题如果某个图标的drawable对象在代码中被直接修改比如设置setColorFilter那么所有引用同一个drawable的页面都会受影响因为它们在内存中共享同一个实例。我遇到过的情况是某个列表页给一张图标设置了setAlpha结果用户跳到另一个页面发现同一个图标透明度也被改了。原因就是Resources加载同一个资源ID时返回的Drawable是同一份带状态和缓存的。解决方案有两个一是修改时使用drawable.mutate()让Drawable独立出一份二是新页面里不要复用旧的drawable实例而是通过资源ID重新获取一次。5.3 动态加载图标getIdentifier的坑与安全替代方案动态加载在主题商店类App里很常见int resId getResources().getIdentifier(ic_home_blue, drawable, getPackageName());这段代码看着方便隐患也不少。第一资源名拼错不会在编译期暴露运行时返回0加载到null丢异常第二每次调用getIdentifier都有字符串匹配开销在循环里调用会拖慢性能第三会把大量资源名暴露在一个字符串池里对于混淆或资源裁剪的场景也不友好。更稳妥的方案是使用ResourcesCompat配合array资源做映射或者用枚举定义图标名与资源ID的对应关系再或者如果主题管理是运营配置的后端下发资源ID或URLApp端解析后加载。整体上运行时动态找资源这种操作能少用就少用。5.4 动态换肤与图标着色避免主题切换时图标变花动态换肤的核心是把资源里的颜色抽成主题属性。前面说过矢量图标可以通过fillColor引用主题色位图则可以用tint统一着色。换肤时如果只是简单遍历页面并重新加载drawable容易出两个问题一是旧drawable被缓存导致颜色不刷新二是select选择态图标没有同步更新结果出现选中态还是旧主题色的情况。我的做法是换肤事件触发后主动清理图片加载库的内存缓存同时给需要变色的控件重新设置tintList或backgroundTintList。如果是用多个Activity的组织方式最好用一套换肤基础设施确保页面重建时能绑定当前主题资源而不是依赖页面自己记住旧颜色。这一块虽然代码量不大但细节非常多建议专人在项目里统一维护不要每人一套思路。6. 高频问题实战排查从缩略图不显示到fileprovider路径异常的一次完整复盘资源管得再好实际开发和线上环境总有些奇怪现象冒出来。我挑选了几个被反复问到、且和PNG/矢量图标相关的高频问题给你一条完整的排查链路和最终方案。6.1 PNG在文件夹里不显示缩略图别急着怀疑资源文件有同事在drawable文件夹里看不到PNG预览以为图片坏了。这类问题大多是Windows系统或Android Studio的缓存问题。先确认一下文件本身是否能正常打开如果能在系统图片查看器里看到那说明资源文件没坏。再看AS左下角的Resource Manager面板如果列表里显示不出来可能是AS缓存索引异常这时候执行File - Invalidate Caches / Restart基本能解决。如果这是Windows系统文件夹里的PNG不显示缩略图可能和系统缩略图缓存损坏有关。不需要重新导出图片重启Windows资源管理器或清理缩略图缓存然后重新打开文件夹即可。真遇到这一步还是不行再检查是不是系统里装了某些第三方看图工具劫持了PNG的图标预览。6.2 资源文件被系统拒绝或找不到fileprovider配置与android/data目录权限不止一个人问过我为什么FileProvider.getUriForFile抛异常或者裁剪头像时访问PNG文件返回FileNotFoundException。这往往是fileprovider的paths配置和实际文件路径不匹配导致的。Android 7.0开始App访问自身外部存储里的文件不能用file://必须通过FileProvider生成content://的URI。常见的配置是在AndroidManifest.xml里注册provider android:nameandroidx.core.content.FileProvider android:authorities${applicationId}.fileprovider android:exportedfalse android:grantUriPermissionstrue meta-data android:nameandroid.support.FILE_PROVIDER_PATHS android:resourcexml/file_paths / /provider对应的res/xml/file_paths.xml里得把你需要共享的目录列出来paths external-path nameexternal_files path. / cache-path namecache path. / /paths很多开发者卡住的原因是把PNG文件写在/sdcard/Android/data/你的包名/files/下面但file_paths里没有配置对应目录或者path写得太具体导致根目录下的其他文件访问不到。配置时建议把握好粒度权限范围越小越安全但也别小到实际路径覆盖不全。你如果在热搜里见过content://com.tencent.wework.fileprovider/external_path/android/data/com这种路径那本质就是某个应用通过FileProvider对外共享文件的URI格式本身就是content://authority/配置路径别名/实际相对路径。出现地址栏位置错乱、文件打不开的情况优先检查的是这个别名和实际路径的映射关系而不是去看文件本身。6.3 图标加载变糊或变模糊密度目录与自适应icon的兼容性排查模糊问题在图标场景里特别常见。先看布局里ImageView的宽高是不是wrap_content如果是它会对齐到当前density对应的尺寸理论上不应该模糊。模糊通常有两种来源一是资源本身尺寸不足比如只提供了xhdpi下的图在xxhdpi设备上被放大拉伸二是自适应图标里只放了anydpi-v26的XML在低版本设备上回退失败系统用了一个缩放的位图导致糊。排查方法很简单先用dumpsys activity top查看当前Activity的资源密度信息再在设备的设置里切一遍不同的显示大小或者用AS的Layout Inspector看实际渲染的bitmap尺寸。如果确认是资源密度不足老老实实补图如果是自适应图标回退问题检查mipmap各密度目录下是否都有传统PNG图标。6.4 切图导出边距过大从PNG透明边界裁剪到Android侧的自动裁切设计师在切图时导出PNG发现图片四周留了一圈白边透明区域放到界面上之后视觉上图标就偏小。解决办法有两个层面PS里切片时勾选裁切透明像素或者导出后统一做一次自动裁切如果已经放到Android工程里了还可以在代码或XML里用android:adjustViewBounds加android:scaleTypefitXY等方式压缩显示区域但这些属于补救。最省事的做法统一要求设计侧在视觉稿里把图标画到安全区域内导出时删掉多余透明边距。因为透明边距不仅影响视觉大小在点击热区判断时也可能造成误触区域扩大。Android官方对可点击图标的最小触摸目标建议是48dp但这是热区不是视觉尺寸两者不能混为一谈。6.5 Android Studio环境问题下载安装、中文语言包与老项目移植最后聊几个和AS环境相关的排查毕竟图标资源管理离不开IDE。AS下载慢通常是因为官方服务器连接不稳定优先用官方镜像或及时更新网络环境。安装后设置中文语言包可以直接在Plugins仓库里搜索Chinese Language Pack下载安装重启即生效。老项目移植到新版AS时常见报错包括Gradle版本不匹配、SDK位置不对、依赖库版本过期等处理原则是先把Gradle和AGP版本对齐到新AS兼容列表里再让依赖逐步升级不要一次全升否则冲突会叠加得很难解。移植项目时资源相关的问题还有一个经典的旧项目的compileSdk太低新版AS创建的资源目录格式比如drawable-anydpi-v26无法识别。这时候优先升级compileSdk并同步处理androidx迁移。资源文件本身一般情况下不会失效但越早完成编译环境的统一后面的管理成本越低。7. 一套可直接复制的资源管理配置模板聊了这么多我最后给出一套我目前实际在用的资源管理模板你可以根据团队情况直接抄走。目录规划res/ drawable/ # 普通图标与背景 common/ # 全局通用资源 login/ # 登录模块 home/ # 首页模块 profile/ # 我的模块 order/ # 订单模块 mipmap-anydpi-v26/ # 自适应图标XML mipmap-mdpi~xxxhdpi/ # 传统启动图标PNG values/ colors.xml themes.xml命名规则类型格式示例说明普通图标ic_home_search_normal.png模块_类型_描述_状态背景图bg_login_btn_pressed.9.png以bg开头.9图尾缀Selectorselector_tab_home.xml以selector开头矢量图标ic_arrow_back.xml命名同普通图标格式为xml构建配置android { compileSdk 34 defaultConfig { minSdk 21 targetSdk 34 } buildTypes { release { minifyEnabled true shrinkResources true } } }资源压缩保留规则如果在代码中动态引用资源需要在res/raw/keep.xml里配置resources xmlns:toolshttp://schemas.android.com/tools tools:keepdrawable/ic_dynamic_icon,layout/activity_dynamic /图片加载配置以Coil为例val imageLoader ImageLoader.Builder(context) .memoryCachePolicy(CachePolicy.ENABLED) .diskCachePolicy(CachePolicy.ENABLED) .respectCacheHeaders(false) .build()这套模板不是什么高深方案但它把命名、分层、混淆、压缩这些事都纳入到一条轨道上。团队里每个人都按照同一套规则操作图标资源就不会变成一团乱麻。我自己在实际项目里的体会是资源管理这件事做得好不会让你在功能上多出什么亮点但做得差每天都会被各种小问题磨掉耐心。一个图标模糊、一张图显示不出来、一次换肤后颜色不对这些单看都是小bug累计起来就是团队效率和线上质量的隐形杀手。先把规范立起来把工具链跑通后面省下来的都是实实在在的时间和风险。