图片是内存消耗大户,针对 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
的哈希表结构,在数据量不大时内存占用更少。