图片是内存消耗大户,针对 Bitmap 的优化至关重要。
按需加载与压缩
BitmapFactory.Options 中的 inSampleSize 属性。根据目标 View 的大小计算出合适的采样率,只加载缩略图到内存,避免加载整张高清大图。实现高效缓存策略
LruCache): 使用最近最少使用算法,将近期用过的图片保留在内存中,快速加载。DiskLruCache): 将图片文件缓存到本地存储,避免重复从网络下载。使用合适的图片格式
JPEG: 适用于非透明图片,可以进行有损压缩以减小文件大小。WebP / AVIF: 在支持的系统版本上,优先使用这些现代图片格式。它们在同等画质下通常比 JPEG 和 PNG 体积更小。频繁的内存分配和垃圾回收(GC)会造成卡顿。通过复用和预分配可以有效缓解此问题。
ListView / RecyclerView 中的复用
ViewHolder 模式,复用已经创建的 View 和 ViewHolder 实例,而不是在 getView() 或 onBindViewHolder() 中频繁创建新对象。预设集合初始容量以避免扩容
ArrayList 这类集合,在添加元素超出当前容量时,会触发自动扩容机制(通常是当前容量的 1.5 倍)。这个过程涉及“创建更大的新数组”和“复制旧数组内容”,会造成瞬时的性能抖动。List<String> list = new ArrayList<>(100); 这样可以一次性分配好足够的空间,从而避免在后续添加元素的过程中发生多次耗时的扩容操作。内存泄漏会导致可用内存越来越少,最终引发 OutOfMemoryError。
警惕静态变量持有长生命周期对象
static Context 或 static View)持有 Activity、Fragment 等具有长生命周期上下文的引用,因为静态变量的生命周期与应用进程相同。正确使用内部类和匿名类
Handler、Thread、AsyncTask)时,应使用静态内部类。如果需要引用外部类(如 Activity),请通过 WeakReference (弱引用) 来持有。及时关闭和回收资源
Cursor、InputStream/OutputStream、Bitmap、OkHttp 的 Response.body() 等需要手动关闭的资源,务必在 finally 块或 try-with-resources 语句中调用其 close() 或 recycle() 方法。监听器的成对注册与反注册
BroadcastReceiver、EventBus、RxJava 的订阅、SensorManager 等监听器,必须在合适的生命周期回调中(如 onPause, onStop, onDestroy)进行反注册,否则会持有 Activity 或 Fragment 的引用导致泄漏。SparseArray 族系替代 HashMap
Map 的键(Key)是整型(int)或长整型(long)时。HashMap<Integer, Object> 会对 int 进行装箱操作,而 SparseArray 直接使用原始类型,无额外开销。HashMap 的哈希表结构,在数据量不大时内存占用更少。