Android 性能调优相关
1. 谈谈代码混淆的步骤开启混淆在模块的build.gradle中设置minifyEnabled true并指定混淆文件proguardFilesgetDefaultProguardFile(proguard-android-optimize.txt),proguard-rules.pro编写混淆规则proguard-rules.pro保留四大组件、自定义 View、实体类用于 JSON 反序列化需保留无参构造器和字段名。保留通过反射、注解、JNI、序列化访问的类或方法。引入第三方库专属混淆规则通常库文档会提供-keep指令。测试对混淆后的包进行充分测试避免ClassNotFoundException或NoSuchMethodError。打包混淆器自动进行代码压缩、类名/方法名短化、配合shrinkResources true压缩资源、移除无效代码。保存映射文件每次发布保存build/outputs/mapping/下的mapping.txt记录了混淆前的类名、方法名、字段和行号的对应关系用于线上堆栈还原崩溃日志。作用减小 APK 体积、加固防破解、删除无用代码。2. 谈谈怎么给 apk 瘦身代码混淆开启 ProGuard / R8移除无用代码。资源压缩shrinkResources true移除未引用资源。图片优化使用 WebP、矢量图VectorDrawable、降低 PNG 质量。避免重复库使用gradle的exclude去重。动态下载部分模块插件化或 AABAndroid App Bundle按需分发。移除不必要的语言资源resConfigs zh。3. 谈谈如何对网络请求进行优化减少请求次数批量接口、合并请求。数据压缩Gzip 压缩请求体 / 响应体。使用缓存HTTP 缓存Cache-Control、本地磁盘缓存。连接复用使用 HTTP/2、OkHttp连接池。弱网优化设置合理超时、重试策略、断点续传。DNS 优化HttpDNS 防劫持、减少 DNS 解析时间。4. 谈谈 App 的电量优化减少网络请求合并请求、使用 GCM/FCM 推送。后台任务避免长时间后台运行使用JobScheduler进行批量处理。减少唤醒次数使用AlarmManager时选非精确setInexactRepeating使用JobScheduler/WorkManager。定位优化按需请求位置使用被动定位requestLocationUpdates合理设置间隔。Sensor 使用及时注销传感器监听。WakeLock及时释放使用acquire/release配对。5. 谈谈你是如何优化 App 启动过程的异步初始化Application中的第三方库延迟或异步初始化使用IdleHandler。减少主线程任务将非立即需要的初始化移到子线程。视觉优化设置主题页windowBackground避免白屏。优化布局首屏布局简单避免嵌套过深。预加载WebView预创建、数据预取。减小 Dex 体积开启混淆、MultiDex 优化。6. 谈谈如何对 WebView 进行优化预初始化提前创建 WebView 并复用。加载优化开启硬件加速、合理设置缓存策略setCacheMode网页缓存、资源缓存、离线缓存。资源拦截本地替换 JS/CSS使用shouldInterceptRequest。进程独立将 WebView 置于单独进程避免内存泄漏影响主进程。销毁时onDestroy中removeAllViews、destroy()。JS 注入优化延迟注入或按需注入。7. Android Native Crash 问题如何分析定位获取日志logcat抓取 crash 日志关注Fatal signal 11 (SIGSEGV)等。tombstone 文件/data/tombstones/下有崩溃堆栈。addr2line用ndk-stack或addr2line解析 so 文件中的地址。Breakpad / Google Breakpad捕获 Native 崩溃生成 minidump 文件分析。常见原因空指针、内存越界、释放后使用、栈溢出、动态库加载失败。8. 谈谈你对 Android 性能优化方面的了解内存优化避免内存泄漏静态引用、Handler、匿名内部类、对象复用、使用LruCache及时回收 Bitmap。LruCache内存缓存工具类基于 LRULeast Recently Used最近最少使用算法优先淘汰最近就少使用的对象启动优化减少Application和首屏onCreate任务、异步加载、优化主题页。卡顿优化避免主线程耗时操作、使用TraceView/Systrace分析。网络优化合并请求、数据压缩、使用缓存、HttpDNS。安装包瘦身混淆、资源压缩、WebP、移除无用资源。绘制优化onDraw中避免创建对象、频繁调用invalidate。布局优化减少层级ConstraintLayout、避免过度绘制、使用merge/ViewStub。9 简要说说 LruCache 的原理LRU 全称最近最少使用算法优先淘汰长时间未使用的数据。底层基于LinkedHashMap开启访问有序模式。核心机制每次get/put访问元素会将当前元素移至队列头部长期不访问的元素会逐步挤到队列尾部缓存达到设定阈值时自动移除尾部最少使用元素。优点可控内存上限、自动淘汰、防止缓存无限膨胀、减少 OOM。适用图片内存缓存、高频本地缓存场景。一句话记忆LruCache 基于 LinkedHashMap 的访问顺序自动淘汰最久未使用的条目。10 为什么推荐用 SparseArray 代替 HashMapKey 类型SparseArray的 Key 为int基本类型无需自动装箱int→Integer节省内存和 CPU。内存结构底层采用数组存储内存占用更小HashMap 是数组 链表 / 红黑树结构冗余、内存开销大。查找效率SparseArray使用二分查找O(log n)小数据量下速度更快。HashMap使用哈希表O(1) 平均。数据量较小时二分查找开销可接受且更省内存。延迟删除机制删除时先标记不立即移动数组减少拷贝开销。适用场景数据量小几百以内且Key 为 int如映射 View ID 到 View。一句话记忆SparseArray 省内存、免装箱适合 Key 为 int 的小数据量场景。11. 谈谈 Android 中内存优化的方式避免内存泄漏静态内部类 弱引用非静态内部类、匿名类持有外部引用、及时注销监听、onDestroy中清空 Handler。Bitmap 优化inSampleSize缩放、inBitmap复用、RGB_565格式。对象池复用对象如Message.obtain。使用数据缓存LruCache、DiskLruCache。使用SparseArray/ArrayMap替代HashMap节省内存。12. 哪些情况下会导致 OOM 问题加载过大图片未缩放直接加载到内存。内存泄漏Activity 未释放大量对象无法回收。创建大量对象循环中频繁new对象。内存碎片频繁分配释放导致大块连续内存不足。长生命周期集合静态List/Map不断添加数据。超大数组一次性加载大量数据到内存。Android 版本差异低版本单个进程内存上限更小。13. 自定义 Handler 时如何有效地避免内存泄漏问题原因非静态内部类 Handler 隐式持有外部 Activity 引用延迟消息导致 Activity 无法回收。解决方案使用静态内部类弱引用持有 Activity。在onStop/onDestroy中调用handler.removeCallbacksAndMessages(null)移除所有消息。示例staticclassMyHandlerextendsHandler{WeakReferenceActivityref;MyHandler(Activityactivity){refnewWeakReference(activity);}OverridevoidhandleMessage(Messagemsg){Activityactref.get();if(act!null){/* 处理 */}}}14. Bitmap 的内存优化方法有哪些/如何避免 Bitmap 的 OOM 问题按需加载图片压缩inSampleSize降低宽高、缩略图、局部加载、大图分块加载只解码显示区域合理格式选用高效格式 WebP、HEIF减少内存占用解码配置inPreferredConfig用RGB_56516位代替ARGB_888832位降低内存。使用缓存三级缓存内存缓存、磁盘缓存、网络控制缓存上限Glide/Coil 复用内存inBitmap复用已分配的内存避免重新分配及时回收recycle()释放 native 内存Android 8.0 后内部自动管理但建议仍调用15. 什么是 ANR触发条件如何避免ANRApplication Not Responding应用无响应主线程阻塞超时Activity 5 秒、BroadcastReceiver 10 秒、Service 20 秒。触发条件输入事件按键/触摸5 秒内未响应广播接收者BroadcastReceiver10 秒内未执行完服务Service20 秒内未启动完成ContentProvider 发布超时常见场景主线程执行网络请求、IO 读写、大文件操作主线程执行复杂计算循环、加密主线程执行数据库大量操作线程死锁导致主线程等待避免方法不在主线程做耗时操作网络、IO、复杂计算使用子线程处理耗时任务Thread、协程避免在主线程中使用锁主线程只做 UI 刷新轻量逻辑优化布局避免过度绘制、频繁的requestLayout使用HandlerThread、IntentService处理后台任务。使用StrictMode检测主线程中的潜在阻塞操作。16. 如何计算一张图片所占的内存空间大小图片内存大小 总像素个数 × 单个像素所占字节总像素 图片宽 × 图片高像素位深举例ARGB_8888每个像素4 字节RGB_565每个像素2 字节ARGB_4444每个像素2 字节补充要点计算的是加载进内存的像素内存不是磁盘文件大小inSampleSize采样压缩后宽高同时缩小倍数内存成倍降低Android 图片内存为 Native 内存容易引发 OOM。17. WebP 和 SVG 特点 Android 使用方案WebP 特点高效压缩体积远小于 JPG/PNG无损 / 有损都支持支持透明、动图画质相近体积更小安卓高版本原生完美兼容减少图片包体积。使用场景图标、商品图、背景图、常规位图替代 PNG/JPG。SVG 特点矢量图放大缩小不失真体积极小纯路径绘制无像素概念不适合复杂大图、色彩丰富图片。使用场景纯色图标、按钮 ICON、简单矢量标识。开发使用WebP直接放置资源目录系统原生加载、Glide 完美支持SVGAndroidStudio 导入矢量图使用VectorDrawable渲染。18. 对于 GIF 图片加载有什么思路和建议使用成熟框架优先 Glide、Coil 原生支持 GIF 解析播放不手写解码。格式替代简单动图优先用 Lottie 矢量动画替代笨重 GIF性能更好。内存限制限制 GIF 分辨率、帧率避免逐帧大图占用大量内存。资源回收页面销毁及时释放 GIF 解码器、停止动画、清空引用。按需播放页面不可见、切后台时暂停 GIF、减少耗电与内存占用。避免频繁循环非必要场景限制播放次数降低 CPU 消耗。19. MVP 中如何处理 Presenter 防止内存泄漏View 层弱引用Presenter 持有 View 时使用WeakReference包裹避免 Activity/Fragment 被强引用。生命周期解绑页面销毁onDestroy/onDestroyView中主动解绑 View置空引用。终止异步任务Presenter 中网络请求、协程、回调页面销毁时统一取消、终止。杜绝静态持有 Presenter 不要使用静态变量持有页面、View 实例。接口隔离 通过 View 接口通信减少强耦合方便统一回收销毁。总结Presenter 弱引用持有 View页面生命周期及时解绑、清空异步任务杜绝长引用绑定。