Android apps often share a limited pool of RAM. When the system runs low on memory, it starts killing background processes to reclaim space. If your app is resource-heavy, it might be the first on the chopping block. To prevent this and provide a smoother user experience, Android provides the onTrimMemory callback. This method allows your app to proactively release resources based on the system's current memory state.
Understanding the onTrimMemory Callback
Introduced in API level 14, onTrimMemory is a tool for fine-grained memory management. Unlike the older onLowMemory, which only triggered when the system was already at a critical point, onTrimMemory provides specific "levels" that tell you exactly how much pressure the system is under.
Implementing the Callback
You can implement this callback in your Activity, Service, ContentProvider, or Application class. The most common approach is implementing it in a custom Application class to manage global resources like image caches or database connections.
class MyApplication : Application() {
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
when (level) {
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> {
// Release UI resources as the app is now in the background
clearLargeImageCache()
}
ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE,
ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> {
// The app is running, but the system is under pressure
// Release non-essential memory
evictUnusedCaches()
}
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND,
ComponentCallbacks2.TRIM_MEMORY_MODERATE,
ComponentCallbacks2.TRIM_MEMORY_COMPLETE -> {
// The system is low on memory and your process is near the
// top of the killable list. Release everything possible.
releaseAllNonEssentialResources()
}
}
}
private fun clearLargeImageCache() {
// Logic to clear memory-intensive bitmaps
}
private fun evictUnusedCaches() {
// Logic to trim LruCache
}
private fun releaseAllNonEssentialResources() {
// Drastic resource cleanup
}
}
Key Memory Levels to Watch
The level parameter provides context. TRIM_MEMORY_UI_HIDDEN is a common one; it triggers when the user navigates away from your app. This is the perfect time to release heavy objects that only the UI needs. TRIM_MEMORY_COMPLETE is the most severe, indicating that your process will likely be killed if memory isn't freed immediately.
Practical Optimization Tips
1. **Evict Caches**: If you use an LruCache, call evictAll() or reduce its max size during high-pressure events.
2. **Dispose of Bitmaps**: Bitmaps are memory-intensive. Nullify references to bitmaps that aren't currently visible or used.
3. **Stop Background Tasks**: If the memory level is critical, consider pausing non-essential background threads or intensive network requests.
4. **Test with ADB**: You can simulate memory pressure using the Android Debug Bridge (ADB) to ensure your logic works as expected.
Using onTrimMemory isn't just about preventing crashes; it is about being a good citizen in the Android ecosystem. By releasing memory when asked, you help the entire system run faster and keep your app alive longer in the background, allowing for quicker resumes when the user returns.