Pipes Feed Preview: Android Developers Blog

  1. Android 17 is here

    Tue, 16 Jun 2026 13:00:00 -0000

    <meta content="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV7zuuXjulHty999mGDWY1kfL8Q9SXjYYWn-7JTpMfVdNP78eb5fW9shOpvVdEqK0WnNp7AhdO0qc7pXAaqcfTwXgOGsfZyqcQv8wyD-9niWBpZuP6ZAPHBSetWenN2lMlRS5wi2d71-n8RCYqrLsFhUCEvM7KeoGLnNaDbiyOZQ0vvyr0O580nXK4Vas/s2048/Metadata%20-%20Static.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></meta> <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV7zuuXjulHty999mGDWY1kfL8Q9SXjYYWn-7JTpMfVdNP78eb5fW9shOpvVdEqK0WnNp7AhdO0qc7pXAaqcfTwXgOGsfZyqcQv8wyD-9niWBpZuP6ZAPHBSetWenN2lMlRS5wi2d71-n8RCYqrLsFhUCEvM7KeoGLnNaDbiyOZQ0vvyr0O580nXK4Vas/s2048/Metadata%20-%20Static.png" style="display: none;" /><div><i>Posted by Matthew McCullough, VP of Product Management, Android Developer</i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5KPJZylMSUXRpKFRUd6oM4fNdEoDRdJzdkzg69P_BVUuIDtXqCqTid6hGH40CoHRw7-f50HsT6rISArklGH982MM4K1jKU16SSymes4JPoE4qOZ5s1lLnkbInpUpdJGu5erAYmSgiefzkkOX_ng3AUJKOzzwC1WMTjk2DxLNia8R1C-ErWc7jT4VP8ew/s4209/Blogger%20Hero%20-%20White.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1253" data-original-width="4209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5KPJZylMSUXRpKFRUd6oM4fNdEoDRdJzdkzg69P_BVUuIDtXqCqTid6hGH40CoHRw7-f50HsT6rISArklGH982MM4K1jKU16SSymes4JPoE4qOZ5s1lLnkbInpUpdJGu5erAYmSgiefzkkOX_ng3AUJKOzzwC1WMTjk2DxLNia8R1C-ErWc7jT4VP8ew/s16000/Blogger%20Hero%20-%20White.png" /></a></div><br /><p><br /></p><p>Today we're releasing Android 17 and making it available on most supported Pixel devices. Look for new devices running Android 17 in the coming months.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjaHGBWXu3yvdXZ-wYQgN6DjN5TEMRIYDJvQDZTOybRZFWsAMhqhl14b9UZmrlXlEIRDioqRc8m3xRjOnQHJPoICkVpCho4qrmKihPbu_SB7dGVNKwlAaX6eWdjLF4VUdGyzGfxtW0ziFggj63e778VVo38qpMKar4E1wuw0MiPCBvBdrTTXCgI1XD04Q/s1080/AfD-Android-17.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1080" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjaHGBWXu3yvdXZ-wYQgN6DjN5TEMRIYDJvQDZTOybRZFWsAMhqhl14b9UZmrlXlEIRDioqRc8m3xRjOnQHJPoICkVpCho4qrmKihPbu_SB7dGVNKwlAaX6eWdjLF4VUdGyzGfxtW0ziFggj63e778VVo38qpMKar4E1wuw0MiPCBvBdrTTXCgI1XD04Q/s320/AfD-Android-17.gif" width="320" /></a></div> <p>Android 17 marks the start of our transition to an intelligence system, putting your apps at the center. It's shifting to an adaptive-first development standard by introducing mandatory large-screen resizability, all while delivering next-generation privacy, security, media, camera, and performance. We'll cover all that in this post, as well as how we're bringing together next generation tools, libraries, and agent skills to help your apps embrace the opportunity.</p> <p>Throughout the past year, from our Canary channel to our Beta releases, we’ve collaborated with you in the developer community to build a platform you and your users can trust. To that end, this moment marks the availability of the source code at the <a href="https://source.android.com/">Android Open Source Project</a> (AOSP). This allows you to <a href="https://cs.android.com/">examine the source code</a> for a deeper understanding of how Android works.</p> <p>Let's dive deeper into Android 17.</p> <h3>An intelligence system</h3> <p>With deep integration between hardware, software and AI, we’re transforming Android from an operating system to an intelligence system. It's about delivering new helpful experiences that anticipate user needs, and it brings more opportunities for engagement with your apps. To that end, Android 17 expands the capabilities of AppFunctions, a platform API with a corresponding Jetpack library. It allows you to contribute your app's unique capabilities as orchestratable "tools" for Android MCP, the on-device equivalent of the <a href="https://modelcontextprotocol.io/">Model Context Protocol</a>. AI agents and assistants (like Google Gemini) can discover and execute AppFunctions to perform workflows on behalf of the user with direct access to the app's local state.</p> <p>The Jetpack library, currently in alpha, makes adding AppFunctions as easy as annotating a class and adding KDoc comments.</p> <pre><code>/** * A note app's [AppFunction]s. */ class NoteFunctions( private val noteRepository: NoteRepository ) { /** * Adds a new note to the app. * * @param appFunctionContext The execution context. * @param title The title of the note. * @param content The note's content. */ @AppFunction(isDescribedByKDoc = true) suspend fun createNote( appFunctionContext: AppFunctionContext, title: String, content: String ): Note { return noteRepository.createNote(title, content) } }</code></pre> <p>We’ve also launched an <a href="http://github.com/android/skills/tree/main/on-device/appfunctions">AppFunctions agent skill</a> that analyzes your app’s key workflows, automatically generates the required Kotlin code, optimizes your KDocs for LLM tool-calling, and provides ADB commands for testing and debugging.</p> <p>The Gemini integration is currently in a private preview with trusted testers, but you can begin preparing your apps now. In addition to ADB commands to execute your AppFunctions, we've provided a <a href="http://github.com/android/appfunctions/releases/initial">test agent app</a> that includes an interface to discover and execute your app functions and simulate an AI agent integration. Join our integration early access program at <a href="http://goo.gle/eap-af">goo.gle/eap-af</a> for a chance to be among the first apps to deploy AppFunctions to production.</p> <h3>Adaptive-first</h3> <p>Your users no longer rely on a single form factor; they transition between phones, foldables, tablets, laptops, automotive displays, and immersive XR environments. Now, with over <a href="https://developer.android.com/blog/posts/adaptive-development-for-the-expanding-android-ecosystem">580 million large screen devices</a> in the hands of users and the <a href="https://blog.google/products-and-platforms/platforms/android/meet-googlebook/">forthcoming launch of Googlebooks</a>, the next generation of ChromeOS built on the Android stack, adaptive is no longer just a technical goal. It’s a massive opportunity to reach highly engaged users, which is one of the reasons we're shifting to an <a href="https://developer.android.com/adaptive-apps">adaptive-first development standard</a>.</p> <h2>No resizability/orientation restrictions on large screens</h2> <p>To ensure apps deliver a premium experience across all form factors, including mobile devices running in desktop mode on connected displays, Android 17 (API level 37) removes the developer opt-out for orientation and resizability restrictions on <a href="https://developer.android.com/guide/topics/large-screens">large screen devices</a> (sw &gt; 600 dp) for apps targeting API level 37. The system will ignore legacy manifest attributes and runtime APIs, including screenOrientation, setRequestedOrientation(), resizeableActivity=false, and aspect ratio constraints (minAspectRatio/maxAspectRatio). Games (based on <a href="https://support.google.com/googleplay/android-developer/answer/9859673?hl=en">app category</a> in Google Play) remain exempt. Your app must be ready to adapt to any window size, respect the user's preferred device posture, and support free-form windowing natively.</p> <h2>Next-gen multitasking: App Bubbles, Bubble Bar, and desktop interactive PiP</h2> <p>Android 17 introduces powerful new windowing capabilities that redefine how users multitask, demanding even greater layout flexibility from your apps:</p> <ul> <li><strong>App Bubbles:</strong> Moving beyond the messaging bubbles API, users can now transform any app into a floating bubble by long-pressing its icon on the launcher. This feature is available across phones, foldables, and tablets, enabling lightweight multitasking for any workflow.</li> <li><strong>The Bubble Bar:</strong> On large screens (tablets and foldables), the system taskbar now includes a dedicated Bubble Bar to organize, transition between, and dock these floating app bubbles.</li> <li><strong>Desktop interactive PiP:</strong> In desktop environments, Android 17 introduces interactive Picture-in-Picture (PiP). Unlike traditional PiP windows which are read-only, these pinned windows remain fully interactive while staying always-on-top of other application windows.</li> </ul> <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg12FRQ31sUiyMj_ZalamTRI4VyI2tMXYKEoRy6b-u0Het272IDbRhznXot7b8AvFJEX-ubw_-pNxyS5JTKPUTBj1CNXwIYkTE906vembUcHeyGzE4Lb72WRyGNF7dOP_aBssNeCplOjEnKAc3d3hkak81LOpG0g9Hlep0AvC11MjdJ1MkqAp7ViUCu2bw/s1600/Bubbles%20(1).gif" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1544" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg12FRQ31sUiyMj_ZalamTRI4VyI2tMXYKEoRy6b-u0Het272IDbRhznXot7b8AvFJEX-ubw_-pNxyS5JTKPUTBj1CNXwIYkTE906vembUcHeyGzE4Lb72WRyGNF7dOP_aBssNeCplOjEnKAc3d3hkak81LOpG0g9Hlep0AvC11MjdJ1MkqAp7ViUCu2bw/s16000/Bubbles%20(1).gif" /></a></div><p style="text-align: center;"><i>App Bubbles and Bubble Bar in action</i></p> <h2>Activity recreation updates</h2> <p>To prevent disruptive state loss and stutter, Android 17 updates the default behavior for Activity recreation. The system will no longer restart activities by default for typical configuration changes that do not require a full UI redraw (including <a href="https://developer.android.com/reference/kotlin/android/content/pm/ActivityInfo#config_keyboard">CONFIG_KEYBOARD</a>, <a href="https://developer.android.com/reference/kotlin/android/content/pm/ActivityInfo#config_keyboard_hidden">CONFIG_KEYBOARD_HIDDEN</a>, <a href="https://developer.android.com/reference/kotlin/android/content/pm/ActivityInfo#config_navigation">CONFIG_NAVIGATION</a>, <a href="https://developer.android.com/reference/kotlin/android/content/pm/ActivityInfo#config_touchscreen">CONFIG_TOUCHSCREEN</a>, and <a href="https://developer.android.com/reference/kotlin/android/content/pm/ActivityInfo#config_color_mode">CONFIG_COLOR_MODE</a>).<br /> Instead, running activities will receive these updates via onConfigurationChanged(), enabling smooth transitions. If your application explicitly relies on a full restart to reload resources for these changes, you must now explicitly opt-in using the new <a href="https://developer.android.com/reference/kotlin/android/R.attr#recreateonconfigchanges">android:recreateOnConfigChanges</a> manifest attribute.</p> <h2>Continue On</h2> <p>Android 17 adds Continue On to help users seamlessly transition a task between Android devices. The user sees a suggestion for the most recently opened app from their mobile device in their tablet taskbar, providing a one-tap affordance to launch the app and deep-link where they left off. Continue on can support app-to-web transitions, including falling back to using the web if the app isn't installed.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc8K42DCZ0VTYpFhTlEazp9_AthhqYdm786k1NFolZrP7HwXk2QlF7UV1CU7ECK9N-CiHSfSbH_E2_cXwL3zUuesP-shpa1nau5QmVWDOQeErnCMtvZUw_wwAHNewZZ5S3811f0n_FNoX4U9kyptZQONM_eDB1AAHaoFjMFgTCC7G1d0X2iRo1MN8sev0/s1920/Continue%20On.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1920" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc8K42DCZ0VTYpFhTlEazp9_AthhqYdm786k1NFolZrP7HwXk2QlF7UV1CU7ECK9N-CiHSfSbH_E2_cXwL3zUuesP-shpa1nau5QmVWDOQeErnCMtvZUw_wwAHNewZZ5S3811f0n_FNoX4U9kyptZQONM_eDB1AAHaoFjMFgTCC7G1d0X2iRo1MN8sev0/s16000/Continue%20On.png" /></a><i>Handoff Suggestion on a Tablet</i></div><p style="text-align: left;"><br /></p> <pre><code>class MyHandoffActivity : Activity() { ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Do stuff ... // Enable handoff setHandoffEnabled(true, null) } // Override and implement onHandoffActivityDataRequested override fun onHandoffActivityDataRequested(handoffRequestInfo: HandoffActivityDataRequestInfo) : HandoffActivityData { // Create and return handoff data } }</code></pre> <h2>Go adaptive-first with Jetpack Compose</h2> <p>To help you adapt your apps to meet the new Android 17 requirements, we've launched the <a href="https://github.com/android/skills/tree/main/jetpack-compose/adaptive">Jetpack Compose adaptive skill</a>. This AI-powered developer workflow helps you implement the best adaptive practices:</p> <ul> <li><strong>Adaptive navigation:</strong> Automatically transition between bottom navigation bars on mobile and edge-anchored navigation rails on large screens using NavigationSuiteScaffold from the Material 3 Adaptive library.</li> <li><strong>Multi-pane layouts:</strong> Implement list-detail and supporting pane layouts natively using Navigation 3 Scenes (ListDetailSceneStrategy and SupportingPaneSceneStrategy) instead of fragile fragment transactions.</li> <li><strong>FlexBox &amp; Grid APIs:</strong> Utilize Compose 1.11's dynamic layout components to easily adjust row and column spans on the fly, ensuring your content always fills the space beautifully.</li> <li><strong>Advanced non-touch input:</strong> Leverage Compose 1.11's enhanced trackpad and mouse support, including native focus rings and new APIs (like TrackpadInjectionScope and performTrackpadInput) to easily test and deliver a true "laptop-class" experience on Googlebooks and Desktop Mode.</li> <li><strong>Dynamic window states:</strong> Leverage Compose's reactive state model to seamlessly adapt your UI when the app transitions from full screen to a floating App Bubble or an interactive Desktop PiP window, ensuring a premium experience even at minimal dimensions.</li> </ul> <h2>Android is Compose-first</h2> <p>Compose offers the easiest way to build adaptive apps, and that's just one of the <a href="https://developer.android.com/develop/ui/compose/first#why-compose-first">many reasons</a> we believe that all Android UI should be built with Compose. To that end, <a href="https://developer.android.com/develop/ui/compose/first">Android development is now Compose-first</a>. All new Android APIs, libraries, tools, and developer guidance will be built exclusively for Jetpack Compose. Legacy View components (in the android.widget package) and View-based Jetpack libraries (like Fragments, RecyclerView, and ViewPager) are now in maintenance mode. They will receive only critical bug fixes, and no new features.</p> <blockquote> <p><strong>TIP</strong><br /> Ready to migrate? Use our AI-driven <a href="https://developer.android.com/develop/ui/compose/migrate/migrate-xml-views-to-jetpack-compose">XML to Compose Migration Skill</a> to automatically analyze your legacy View layouts and convert them into highly-adaptive Compose code.</p> </blockquote> <h3>Performance &amp; efficiency</h3> <p>App performance means a smooth user interface, fast app start times, and efficient multitasking; Android 17 has impactful improvements in all of these areas.</p> <h2>App memory limits</h2> <p>Memory usage is one of the silent foundations of overall performance. When a foreground app or service grows unchecked, memory management spikes CPU and battery utilization and eventually leads to the termination of other well-behaved cached apps and background jobs, ultimately forcing slower cold starts and impaired multitasking.&nbsp;</p> <p>Starting in Android 17, the system will enforce strict app memory limits based on a device's total RAM, abruptly terminating offending processes. New things to help you navigate these tighter requirements:</p> <ul> <li><strong>R8 Optimizer:</strong> The R8 optimizer significantly reduces your app's bytecode memory footprint by shrinking classes, methods, and fields into shorter names, and stripping out unused code and resources. Use R8 in full mode along with the new <a href="https://developer.android.com/topic/performance/app-optimization/r8-configuration-analyzer">R8 configuration analyzer</a> to make sure your app is getting the most from R8.<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQePgjeISaotpA-miDPKel-qgAYtepLjMMBaiKZQqTf_iYRTJurn_iAFdC7utLnKRKAh9OhSjF_D83skA2PPg7xts0ORX7aVxBkoax6b9uEPqTlGiY_sh8Xv7U1pr0h4Nm8FLo-h3IJD8FhTJc-gOtpBwyLCnDBUPRJAuaaBjsIOhvUmTXFSna0ykksak/s2048/R8%20Configuration%20Analyzer.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="397" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQePgjeISaotpA-miDPKel-qgAYtepLjMMBaiKZQqTf_iYRTJurn_iAFdC7utLnKRKAh9OhSjF_D83skA2PPg7xts0ORX7aVxBkoax6b9uEPqTlGiY_sh8Xv7U1pr0h4Nm8FLo-h3IJD8FhTJc-gOtpBwyLCnDBUPRJAuaaBjsIOhvUmTXFSna0ykksak/s16000/R8%20Configuration%20Analyzer.png" /></a></div></li></ul><div><span style="color: #0000ee;"><u><br /></u></span></div><div><span style="color: #0000ee;"><u><br /></u></span></div><div><br /></div><div><br /></div><div style="text-align: center;">The R8 Configuration Analyzer</div><ul><li><strong>LeakCanary in Android Studio Panda:</strong> The profiler now features native LeakCanary integration as a dedicated task, fully integrated with your IDE and source code.</li> <li><strong>ApplicationExitInfo:</strong> If your app is terminated by these limits, getDescription() from ApplicationExitInfo will return "MemoryLimiter:AnonSwap".</li> <li><strong>On-Device Anomaly Detection:</strong> Part of ProfilingManager, you can leverage trigger-based profiling using TRIGGER_TYPE_ANOMALY to automatically capture heap dumps when the memory limit is reached.</li> </ul> <pre><code>val profilingManager = applicationContext .getSystemService(ProfilingManager::class.java) val triggers = ArrayList&lt;ProfilingTrigger&gt;().apply { add(ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_ANOMALY).build()) } profilingManager.addProfilingTriggers(triggers)</code></pre> <p>And, we're working to surface more in-field memory metrics to you within Google Play Console.</p> <h2>Generational garbage collection</h2> <p><a href="https://developer.android.com/about/versions">Android 17</a> introduces more frequent, less resource-intensive young-generation collections to <a href="https://developer.android.com/guide/platform#art">ART</a>'s Concurrent Mark-Compact garbage collector (GC). By separating short-lived objects from stable, long-lived ones, the system runs frequent, lightweight "young-generation" sweeps rather than expensive full-heap scans, drastically reducing CPU usage, power drain, and UI stutter. Our testing has shown significant improvements in GC interference with application threads and a reduction in the maximum memory resident set size (RSS). ART improvements are also available to over a billion devices running Android 12 (API level 31) and higher through Google Play System updates.</p> <h2>Lock-Free MessageQueue</h2> <p>For apps targeting SDK 37 or higher, the core <a href="https://developer.android.com/reference/android/os/MessageQueue"><b>android.os.MessageQueue</b></a> now implements a lock-free architecture, significantly reducing missed frames, improving app startup time, and radically improving the performance of busy queues in multithreaded scenarios. Note: This can break apps that use reflection on private <a href="https://developer.android.com/reference/android/os/MessageQueue"><b>MessageQueue</b></a> fields and methods.&nbsp; The <a href="https://developer.android.com/reference/android/os/TestLooperManager#peekWhen()"><b>peekWhen</b></a> and <b><a href="https://developer.android.com/reference/android/os/TestLooperManager#poll()">poll</a> </b>APIs have been added to <a href="https://developer.android.com/reference/android/os/TestLooperManager"><b>TestLooperManager</b></a> for instrumentation testing without relying on <a href="https://developer.android.com/reference/android/os/MessageQueue"><b>MessageQueue</b></a> internals.</p> <h2>Static final fields now truly final</h2> <p>Starting from Android 17, apps targeting SDK 37 or higher won’t be able to modify “static final” fields, allowing the runtime to apply performance optimizations more aggressively. An attempt to do so via reflection (or deep reflection) will lead to an IllegalAccessException being thrown. Modifying them via JNI’s <b><code>SetStatic&lt;Type&gt;Field</code></b> methods family will immediately crash the application.</p> <h2>Custom notification view restrictions</h2> <p>To reduce memory usage we are further restricting the size of <a href="https://developer.android.com/develop/ui/views/notifications/custom-notification">custom notification views</a>. This update closes a loophole that allows apps to bypass existing limits using URIs. This behavior is gated by the target SDK version and takes effect for apps targeting API 37 and higher.</p> <h3>Privacy &amp; Security</h3> <p>Maintaining user trust is at the heart of the Android ecosystem. Android 17 introduces robust features that protect sensitive data while simplifying user experiences.</p> <h2>Privacy-preserving choices</h2> <p>Historically, apps required broad, permanent permissions to access information like contacts, precise location and media files. Android 17 continues the shift toward privacy-preserving choices that grant temporary, session-based access only to the data the user explicitly selects:</p> <ul> <li><strong>System-Level Contact Picker:</strong> Utilizing <code>ACTION_PICK_CONTACTS</code>, apps can request temporary access only to specific fields (e.g., email or phone number) chosen by the user, eliminating the need for the broad <code>READ_CONTACTS</code> permission. It also fully supports work/personal profile separation.</li> <li><strong>Customizable Photo Picker aspect ratio:</strong>&nbsp;Using<b><code>PhotoPickerUiCustomizationParams</code></b>, you can customize the system photo picker to show thumbnails in portrait mode. This is perfect for apps that always display photos and videos in portrait such as video based social media apps.</li> <li><strong>System-rendered Location Button:</strong> A new system-rendered location button that you can embed in your app grants precise location access for the current session only.</li> <li><strong>EyeDropper API:</strong> A new system-level API, <code>ACTION_OPEN_EYE_DROPPER</code>, allows your app to create a system-powered eyedropper enabling the user to select color from any pixel on the display. This provides a secure, privacy-preserving color-picking experience that eliminates the need for broad, sensitive screen capture or media projection permissions.</li> </ul> <pre><code>val eyeDropperLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -&gt; if (result.resultCode == Activity.RESULT_OK) { val color = result.data?.getIntExtra(Intent.EXTRA_COLOR, Color.BLACK) // Use the picked color in your app } } fun launchColorPicker() { val intent = Intent(Intent.ACTION_OPEN_EYE_DROPPER) eyeDropperLauncher.launch(intent) }</code></pre> <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8m_oR9WymjE9G26nGUCqdhS9GrBd6FXN3ujWbjq7ECD6OMGhS4xUApWkAWpPpRef7lwLhsRE2jYL9FADoF_FX2eMXD-0hp9JVaCzrDhfU8RYJ9qv-Ds9YIwyQK7yHKidW0oOtX1rpg2pG9x2yNp3UkGJDPqUlHX7hiLb-bvDue67FPZK1O-22SuXbO8I/s1267/Eyedropper%20Tester.webp" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="1267" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8m_oR9WymjE9G26nGUCqdhS9GrBd6FXN3ujWbjq7ECD6OMGhS4xUApWkAWpPpRef7lwLhsRE2jYL9FADoF_FX2eMXD-0hp9JVaCzrDhfU8RYJ9qv-Ds9YIwyQK7yHKidW0oOtX1rpg2pG9x2yNp3UkGJDPqUlHX7hiLb-bvDue67FPZK1O-22SuXbO8I/w640-h360/Eyedropper%20Tester.webp" width="640" /></a></div><h3><br /></h3><h3><br /></h3><h3><br /></h3><h3><br /></h3><h3><br /></h3><h3><br /></h3><h3><br /></h3><h3><br /></h3><h3><br /></h3><h3 style="text-align: center;"><span id="docs-internal-guid-0ea8e748-7fff-dc26-5289-d5a9513c6997" style="font-weight: normal;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant: normal; vertical-align: baseline; white-space: pre-wrap;"><i>Picking a color from anywhere on the screen with the system EyeDropper</i></span></span></h3><h2>Local network access</h2> <p>Apps targeting Android 17 now either require the <code><a href="https://developer.android.com/reference/kotlin/android/Manifest.permission#access_local_network">ACCESS_LOCAL_NETWORK</a></code> runtime permission or the use of system-mediated, privacy-preserving device pickers for local network communication, such as talking to smart home devices or casting receivers. Because <code>ACCESS_LOCAL_NETWORK</code> falls under the existing <code><a href="https://developer.android.com/reference/android/Manifest.permission_group#NEARBY_DEVICES">NEARBY_DEVICES</a></code> permission group, users who have already granted other <code><a href="https://developer.android.com/reference/android/Manifest.permission_group#NEARBY_DEVICES">NEARBY_DEVICES</a></code> permissions will not be prompted again. </p> <h2>SMS OTP protection</h2> <p>Android 17 expands SMS one-time-password (OTP) protection by delaying access to SMS messages for three hours:</p> <ul> <li>WebOTP Format: <a href="https://developer.android.com/about/versions/17/behavior-changes-all#sms-otp-all-apps">Delayed for all apps that are not the intended recipient (domain mismatch)</a>.</li> <li>Standard SMS OTP: <a href="https://developer.android.com/about/versions/17/behavior-changes-17#sms-otp-protection">Delayed for all apps targeting SDK 37+</a>.</li> <li>Exemptions: Default SMS, assistant, and connected companion apps are exempt. Apps are strongly encouraged to migrate to the <a href="https://developer.android.com/identity/sms-retriever">SMS Retriever</a> or <a href="https://developers.google.com/identity/sms-retriever/user-consent/overview">SMS User Consent APIs</a>.</li> </ul> <h2>Post-Quantum Cryptography (PQC)</h2> <p>Android 17 is ready for the next generation of cryptographic security:</p> <ul> <li>Keystore Integration: Supported devices can generate ML-DSA (Module-Lattice-Based Digital Signature Algorithm) keys in secure hardware to produce quantum-safe signatures, exposed via standard JCA APIs.</li> <li>Hybrid APK Signing: Introducing the v3.2 APK Signature Scheme, which combines classical signatures with ML-DSA signatures to secure app delivery.</li> </ul> <h2>Safer native dynamic code loading&nbsp;</h2> If your app targets SDK 37 or higher, the Safer Dynamic Code Loading (DCL) protection <a href="https://developer.android.com/about/versions/14/behavior-changes-14#safer-dynamic-code-loading">introduced in Android 14</a> for DEX and JAR files now extends to native libraries. All native files loaded using System.load must be marked as read-only. Otherwise, the system throws UnsatisfiedLinkError <h2>Smarter password protection for physical inputs</h2> <p>With Android 17, we're making it safer to enter passwords, PINs, and other secrets when using a physical keyboard by no longer showing the last typed character by default.</p> <p>Users can still easily customize these display settings to match their preferences (availability may vary by device manufacturer).</p> <p>These enhanced privacy protections are automatically supported byAndroid's built-in SDK components and will be supported in Compose 1.12 for SecureTextFields. </p> <h3><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFjWXyRLybiLVAIrIm1_60XHXhPmpB1QEph7AuqsGHs-NihIDRFbUgBh32gUKxo30173W-RpEInX9hmYFVnW5V8ZqtM3n_CzxlT0B0PVQr0LSOuOi7x2kZgN_jHRRlYJ7bYInZllvUGNoA_SrXkNi5wwHvUghUcnl0Gsgx_-ts4QEHq_KdbEYgWCg92xA/s798/Hide%20First%20Letter.gif" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="449" data-original-width="798" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFjWXyRLybiLVAIrIm1_60XHXhPmpB1QEph7AuqsGHs-NihIDRFbUgBh32gUKxo30173W-RpEInX9hmYFVnW5V8ZqtM3n_CzxlT0B0PVQr0LSOuOi7x2kZgN_jHRRlYJ7bYInZllvUGNoA_SrXkNi5wwHvUghUcnl0Gsgx_-ts4QEHq_KdbEYgWCg92xA/s16000/Hide%20First%20Letter.gif" /></a></div></h3><h3><br /></h3><h3><br /></h3><h3><br /></h3><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><i><div style="text-align: center;"><i>Smarter password protection for physical inputs</i></div></i><div><br /></div><h2 style="text-align: left;">Media and camera features that empower creators and delight users </h2><p>Android 17 introduces new <a href="https://blog.google/products-and-platforms/platforms/android/android-17-creator-features/">creator features</a> that give access to pro-quality cameras and media, all while improving the experience for consumers.</p> <ul> <li><a href="https://developer.android.com/media/platform/integrate-eclipsa-video">Eclipsa Video</a>: HDR video standard built upon the <a href="https://github.com/SMPTE/st2094-50">SMPTE ST 2094-50 specification</a> that introduces new metadata to help devices adapt content for their display headroom and ambient light conditions, as well as improve the simultaneous display of standard and HDR content.</li> <li>RAW14 image format: New support for the <a href="https://developer.android.com/reference/kotlin/android/graphics/ImageFormat#raw14">RAW14 image format</a> provides a way for your professional camera app to capture the highest level of detail and color depth from compatible camera sensors.</li> <li>Vendor-defined camera extensions: Vendor-defined extensions enable hardware partners to define and implement custom camera extension modes, providing access to the best and latest camera features.</li> <li>Extended HE-AAC software encoder: A new system-provided Extended HE-AAC software encoder, supports both low and high bitrates using unified speech and audio coding, providing significantly better audio quality for voice messages in low-bandwidth conditions, including support for loudness metadata.</li> <li><a href="https://developer.android.com/guide/topics/media/media-formats#video-formats">Versatile Video Coding (H.266)</a>: Enables OEMs to add codec support by defining the <a href="https://developer.android.com/guide/topics/media/media-formats#video-formats">video/vvc</a> MIME type in <a href="https://developer.android.com/reference/android/media/MediaFormat"><code>MediaFormat</code></a>, adding new VVC profiles in <a href="https://developer.android.com/reference/android/media/MediaCodecInfo"><code>MediaCodecInfo</code></a>, and integrating support into <a href="https://developer.android.com/reference/android/media/MediaExtractor"><code>MediaExtractor</code></a>.</li> <li>Camera device type: New APIs that query the underlying device type to identify if a camera is built-in hardware, an external USB webcam, or a virtual camera.</li> <li>Constant Quality for Video Recording: <a href="https://developer.android.com/reference/android/media/MediaRecorder#setVideoEncodingQuality(int)"><code>SetVideoEncodingQuality</code></a> in <a href="https://developer.android.com/reference/android/media/MediaRecorder"><code>MediaRecorder</code></a> configures a constant quality (CQ) mode for video encoders to ensure uniform visual fidelity across the entire video.</li> </ul> <h2>Better support for hearing aids</h2> <ul> <li>Bluetooth LE Audio hearing aid support: Android now includes a specific device category for Bluetooth Low Energy (BLE) Audio hearing aids with the new <a href="https://developer.android.com/reference/android/media/AudioDeviceInfo#TYPE_BLE_HEARING_AID"><code>AudioDeviceInfo.TYPE_BLE_HEARING_AID</code></a> constant, so your app can distinguish hearing aids from regular headsets to provide a tailored experience for users with assistive listening devices.</li> <li>Granular audio routing for hearing aids: Android 17 allows users to independently manage where specific system sounds are played. They can choose to route notifications, ringtones, and alarms to connected hearing aids or the device's built-in speaker, helping to avoid unwanted in-ear interruptions while maintaining a Bluetooth connection for hearing aid management apps.</li> </ul> <h2>CameraX and Media3</h2> <p><a href="https://developer.android.com/jetpack/androidx/releases/camerax">CameraX</a> and <a href="https://developer.android.com/jetpack/androidx/releases/media3">Media3</a> have been updated for Android 17. They are there to do the heavy lifting, smoothing the rough edges of media development and simplifying building reliable camera capture, smooth media playback, and creative and complex editing experiences. </p> <p>We've released an <a href="https://github.com/android/skills/tree/main/camera">agent skill</a> that can migrate legacy Android camera implementations (Camera1 or raw Camera2 APIs) to CameraX.</p> <p>Note: You'll need to update your CameraX version to either 1.5.2 or 1.6.0+ to avoid a crash related to an added dynamic range mode on Android 17 devices.</p> <h3>Get your apps, libraries, tools, and game engines ready!</h3> <p>If you develop an Android SDK, library, tool, or game engine, it's critical to prepare any necessary updates now to prevent your downstream app and game developers from being blocked by compatibility issues and allow them to target the latest SDK features. Please let your downstream developers know if updates are needed to fully support Android 17.</p> <p>Testing involves installing your production app or a test app making use of your library or engine using Google Play or other means onto a device or emulator running Android 17 Beta 4. Work through all your app's flows and look for functional or UI issues. Each release of Android contains platform changes that improve privacy, security, and overall user experience; review the app impacting behavior changes for apps <a href="https://developer.android.com/about/versions/17/behavior-changes-all">running on</a> and <a href="https://developer.android.com/about/versions/17/behavior-changes-17">targeting</a> Android 17 to focus your testing, including the following:</p> <ul> <li>Resizability on large screens: Once you target Android 17 (SDK 37), you can no longer opt out of maintaining orientation, resizability and aspect ratio constraints <a href="https://developer.android.com/about/versions/17/changes/ff-restrictions-ignored">on large screens</a>.</li> <li>Dynamic code loading: If your app targets SDK 37 or higher, the Safer Dynamic Code Loading (DCL) protection <a href="https://developer.android.com/about/versions/14/behavior-changes-14#safer-dynamic-code-loading">introduced in Android 14 </a>for DEX and JAR files now extends to native libraries. All native files loaded using System.load() must be marked as read-only. Otherwise, the system throws UnsatisfiedLinkError.</li> <li>Enable CT by default: <a href="https://developer.android.com/privacy-and-security/security-config#CertificateTransparencySummary">Certificate transparency (CT)</a> is enabled by default. (On Android 16, CT is available but apps had to <a href="https://developer.android.com/privacy-and-security/security-config#certificateTransparency">opt in</a>.)</li> <li>Local network protections: Apps targeting SDK 37 or higher have <a href="https://developer.android.com/privacy-and-security/local-network-permission#android-17-enforcement">local network access blocked by default</a>. Switch to using privacy preserving pickers if possible, and use the new <a href="https://developer.android.com/reference/kotlin/android/Manifest.permission#access_local_network"><b><code>ACCESS_LOCAL_NETWORK</code></b>permission for broad, persistent access.</li> <li>Background audio hardening: Starting in Android 17, the audio framework enforces <a href="https://developer.android.com/about/versions/17/changes/bg-audio">restrictions on background audio interactions</a> including audio playback, <a href="https://developer.android.com/media/optimize/audio-focus">audio focus</a> requests, and <a href="https://developer.android.com/reference/android/media/AudioManager#adjustStreamVolume(int,%20int,%20int)">volume change</a> APIs. Based on your feedback, we’ve made some changes since beta 2, including targetSDK gating while-in-use FGS enforcement and exempting alarm audio. Full details available in the <a href="https://developer.android.com/about/versions/17/changes/bg-audio">updated guidance</a>.</li> <li>NPU access declaration: Apps targeting Android 17 that need to directly access the NPU must declare&nbsp;<a href="https://developer.android.com/reference/kotlin/android/content/pm/PackageManager#feature_neural_processing_unit">FEATURE_NEURAL_PROCESSING_UNIT</a> in their manifest to avoid being blocked from accessing the NPU. This includes apps that use the <a href="https://ai.google.dev/edge/litert/next/npu">LiteRT NPU delegate</a>, vendor-specific SDKs, as well as the deprecated <a href="https://developer.android.com/ndk/guides/neuralnetworks">NNAPI</a>.</li> </ul> <h3>Get started with Android 17</h3> <p>Your Pixel device should get Android 17 shortly if you haven't already been on the Android Beta. If you don’t have a Pixel device, you can <a href="https://developer.android.com/about/versions/17/get#on_emulator">use the 64-bit system images with the Android Emulator</a> in Android Studio. If you are currently on Android 17 Beta 4.1 and have not yet taken an Android 17 QPR1 beta, you can opt out of the program and you will then be offered the release version of Android 17 over the air.</p> <h3>Getting the Android 17 beta on partner devices</h3> <p>Android 17 is available in beta on handset, tablet, and foldable form factors <a href="https://developer.android.com/about/versions/17/devices">from partners</a> including Honor, iQOO, Lenovo, OnePlus, OPPO, Realme, Sharp, vivo, and Xiaomi.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy5cwRcpdR2j-1KMzQPpsxvIODRLlVkaFNQEIQoNaPQa4X4rgEna5imminlwFdcSJ3xihXdUSFouOC0-ZKyK1A53cBmoaU03au-FjfsqkPXm0tPLtOaWT_7z8tqnMmQjFOr-YIKeP3BMVq8Hmd7yH0zllW1aFMuiW6AAAcDUVL7aIyCAIZUs0d_0VMdF4/s1653/android-17-beta-partners.jpg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="624" data-original-width="1653" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy5cwRcpdR2j-1KMzQPpsxvIODRLlVkaFNQEIQoNaPQa4X4rgEna5imminlwFdcSJ3xihXdUSFouOC0-ZKyK1A53cBmoaU03au-FjfsqkPXm0tPLtOaWT_7z8tqnMmQjFOr-YIKeP3BMVq8Hmd7yH0zllW1aFMuiW6AAAcDUVL7aIyCAIZUs0d_0VMdF4/s16000/android-17-beta-partners.jpg" /></a></div><br /><h3><br /></h3> <p>For the best development experience with Android 17, we recommend that you use the latest Canary build of <a href="https://developer.android.com/studio/preview">Android Studio Quail</a>. Once you’re set up, here are some of the things you should do:</p> <p>Test your current app for compatibility, learn whether your app is <a href="https://developer.android.com/about/versions/17/behavior-changes-all">affected by changes in Android 17</a>, and install your app onto a device or <a href="https://developer.android.com/studio/run/emulator">Android Emulator</a> running Android 17 and extensively test it.</p> <p>Thank you again to everyone who participated in our Android developer preview and beta program. We're looking forward to seeing how your apps take advantage of the updates in Android 17, and have plans to bring you updates in a fast-paced release cadence going forward.</p> <p>For complete information on Android 17 please visit the <a href="https://developer.android.com/about/versions/17">Android 17 developer site</a>.</p><br /><br />
  2. Prioritizing Memory Efficiency: Essential Steps for Android 17

    Tue, 02 Jun 2026 19:00:00 -0000

    <meta content="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCIAoJpwUITPS5C3_eTksMsaslwqPk7SIEQHkwEkGv8572ccdIKcdv6kNC1BOSJPAZTgX5m3liMMv4zdK58e5dWRhUfo39uas23LuhEWf13TFnDTdw-Z5mWn4JarSnC8yCET8Sw15zSF-jQ5zwALriacGK6IjAGxNg61sFtSxzndjvqXxZtJt4qxuzd9A/s2048/Engineering-Memory-Blog-Meta-3.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></meta> <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCIAoJpwUITPS5C3_eTksMsaslwqPk7SIEQHkwEkGv8572ccdIKcdv6kNC1BOSJPAZTgX5m3liMMv4zdK58e5dWRhUfo39uas23LuhEWf13TFnDTdw-Z5mWn4JarSnC8yCET8Sw15zSF-jQ5zwALriacGK6IjAGxNg61sFtSxzndjvqXxZtJt4qxuzd9A/s2048/Engineering-Memory-Blog-Meta-3.png" style="display: none;" /> <div class="separator" style="clear: both; text-align: left;"> <em>Posted by Alice Yuan, Developer Relations Engineer, Ajesh Pai, Developer Relations Engineer, and Fung Lam, Developer Relations Engineer</em> </div> <div class="separator" style="clear: both; text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhanYZz4QpaDuwP7y_ZVGCUh6TpdQxS65pBcYr-Qkawd9YFS587tnIUPnqDROlxIXzgdz6GGxluR3LzH8ZabQPWz382FDEOEDpK3GxUFywn0A54JXFtUwDPaeI0JnFhEl-6NRrcjKeFPMLozNQv_An9OcWEUA-rmXfOhWvIKRrptdblGEZHERD0P-ynFcc/s4209/Engineering-Memory-Blog-3.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"> <img border="0" data-original-height="1253" data-original-width="4209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhanYZz4QpaDuwP7y_ZVGCUh6TpdQxS65pBcYr-Qkawd9YFS587tnIUPnqDROlxIXzgdz6GGxluR3LzH8ZabQPWz382FDEOEDpK3GxUFywn0A54JXFtUwDPaeI0JnFhEl-6NRrcjKeFPMLozNQv_An9OcWEUA-rmXfOhWvIKRrptdblGEZHERD0P-ynFcc/s16000/Engineering-Memory-Blog-3.png" /> </a> </div> <p style="text-align: left;"> While app performance is often equated with a smooth UI and fast start times, memory serves as the silent foundation upon which these visible metrics are built. It's no secret that we're seeing a shift where device memory is more important than ever. Not only have we made strides in Android memory optimizations with Android 17, we're providing the tooling and API support to help you stay ahead of stricter memory requirements later this year. </p> <p style="text-align: left;"> To ensure device stability, starting in Android 17, the system will begin enforcing app memory limits based on the device's total RAM. If an app exceeds those limits, Android will kill the process with no associated stack trace. </p> <div style="text-align: left;"> Beyond these forced terminations, unoptimized memory usage inevitably degrades the user experience. When the app approaches heap memory limits, it triggers frequent garbage collection—leading to noticeable UI stutters. Furthermore, when a device runs out of available memory, the system scrambles to reclaim pages, causing CPU strain, UI latency, and battery drain. If the memory shortage is too severe, it can cause Low Memory Killer (LMK) events that abruptly terminate background processes and force apps to have slow cold starts and lose user state. </div> <div style="text-align: left;"> <p style="text-align: left;">To build highly performant apps and avoid these forced terminations, we recommend that you adopt the following memory optimization strategies:</p> <ol style="text-align: left;"> <li><a href="#Maximize">Maximize bytecode optimization with R8</a></li> <li><a href="#Optimize">Optimize image loading</a></li> <li><a href="#Detect">Detect and fix memory leaks with Android Studio</a></li> <li><a href="#Trim">Trim memory when app leaves visible state</a></li> <li><a href="#Advanced">Advanced memory observability with ProfilingManager</a></li> </ol> </div> <br /> <div> <div class="separator" style="clear: both; text-align: center;"> <iframe allowfullscreen="" class="BLOG_video_class" height="450" src="https://www.youtube.com/embed/fOXJR5qLq54" style="border: 0; height: 450px; width: 100%;" width="100%" youtube-src-id="fOXJR5qLq54"></iframe> </div> <div style="text-align: center;"> <em>A condensed version of this blog post is also available in video format, go check it out!</em> </div> <h3 style="text-align: left;">Understanding Android 17 app memory limits</h3> <p style="text-align: left;">App memory limits are being introduced in Android 17 to prevent "one bad actor" from destroying the multitasking experience and stability of the user’s entire device.</p> <p style="text-align: left;">Here is a breakdown of the reasons driving this architectural change:</p> <div style="text-align: left;"> <ul style="text-align: left;"> <li><b>Preventing cascading kills:</b> When an app becomes bloated or leaks memory while holding a privileged state (e.g. it’s running a Foreground Service), it is initially shielded from the system's Low Memory Killer (LMK). As this single app grows unchecked and hoards RAM, the LMK is forced to compensate by killing off dozens of smaller, well-behaved cached apps and background jobs to reclaim space for the memory hog.</li> <li><b>Preserving multitasking and user state:</b> When the system is forced to purge cached apps to accommodate a single leaking process, the multitasking experience is severely degraded. Users returning to prior cached applications encounter sluggish cold starts instead of near-instant warm resumes. This inefficiency generates more CPU strain and accelerates battery depletion. It can also destroy the user’s context in recently used apps, such as scroll positions, navigation stacks, and in-game progress.</li> </ul> <div style="text-align: left;"> <p>To determine if your app session was impacted by these constraints in the field, you can call <a href="https://developer.android.com/reference/android/app/ApplicationExitInfo#getDescription%28%29" target="_blank">getDescription()</a> within <a href="https://developer.android.com/reference/android/app/ApplicationExitInfo" target="_blank">ApplicationExitInfo</a>. If the system applied a limit, the exit reason is reported as <a href="https://developer.android.com/reference/android/app/ApplicationExitInfo#REASON_OTHER" target="_blank">REASON_OTHER</a> and the description string will contain "MemoryLimiter:AnonSwap". You can also leverage <a href="https://developer.android.com/topic/performance/tracing/profiling-manager/trigger-based-capture" target="_blank">trigger-based profiling</a> using <a href="https://developer.android.com/about/versions/17/features#anomaly-profiling-trigger" target="_blank">TRIGGER_TYPE_ANOMALY</a> to automatically capture heap dumps when the memory limit is reached. Furthermore, Android is actively working to surface more in-field memory metrics to developers within the Google Play Console.</p> <p>We have also expanded our <a href="https://developer.android.com/about/versions/17/behavior-changes-all#app-memory-limits" target="_blank">memory limits documentation</a> to include local debugging commands, allowing you to simulate memory constraints in your local environment and validate your application's behavior under any memory limit enforcement.&nbsp;</p> </div> </div> </div> <div style="text-align: left;"> <h3 id="Maximize" style="text-align: left;">Maximize bytecode optimization with R8</h3> <p style="text-align: left;">A highly effective way to reduce your app's memory footprint is to enable the R8 optimizer. By shrinking classes, methods, and fields into shorter names and stripping out unused code and resources, R8 significantly reduces your app's memory footprint by minimizing the amount of resident code required during execution.&nbsp;</p> <p style="text-align: left;">R8 minimizes resident code, shrinking the memory footprint and lowering LMK termination risk. This results in more frequent warm starts over slow cold starts. Additionally, streamlined bytecode reduces main-thread CPU overhead, directly cutting ANR rates for a more fluid user experience. For example, the digital bank <a href="https://developer.android.com/blog/posts/monzo-boosts-performance-metrics-by-up-to-35-with-a-simple-r8-update" target="_blank">Monzo</a> enabled full R8 optimization and saw a 35% reduction in their ANR rate, a 30% improvement in cold start rate, and a 9% reduction in overall app size.</p> </div> <div class="separator" style="clear: both; text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB61hi7-o6RYAHNOoIg1egyi6iU3iGtLbwfOb-s6r_PadBV2LZzvYtcdD00iwcApjnqmwOssOLFSHv8MG_es8WJWaJUPaO6rMY4ZcINSBFROo_1Di3LVMvIEhPldpzQsUOxV1Z7VfPwvej2fa9a7yCNwBdGOGw2LMLtPrCST6InlqF1xHds30rS76C9no/s2500/pic1-IO26_113_TSV-monzo-casestudy.jpg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"> <img border="0" data-original-height="1406" data-original-width="2500" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB61hi7-o6RYAHNOoIg1egyi6iU3iGtLbwfOb-s6r_PadBV2LZzvYtcdD00iwcApjnqmwOssOLFSHv8MG_es8WJWaJUPaO6rMY4ZcINSBFROo_1Di3LVMvIEhPldpzQsUOxV1Z7VfPwvej2fa9a7yCNwBdGOGw2LMLtPrCST6InlqF1xHds30rS76C9no/s16000/pic1-IO26_113_TSV-monzo-casestudy.jpg" /> </a> </div> <div style="text-align: center;"> <i>The digital bank <a href="https://developer.android.com/blog/posts/monzo-boosts-performance-metrics-by-up-to-35-with-a-simple-r8-update" target="_blank">Monzo</a> enabled full R8 optimization and boosted performance metrics by up to 35%.</i> </div> <div> <p style="text-align: left;">To properly configure R8 in your <code>build.gradle</code> file:</p> <ul style="text-align: left;"> <li>Set <code>isShrinkResources = true</code> and <code>isMinifyEnabled = true</code>.</li> <li>Use <code>proguard-android-optimize.txt</code> instead of the legacy <code>proguard-android.txt</code>, which actually prevents optimizations and is no longer supported in Android Gradle Plugin 9.</li> <li>Remove <code>android.enableR8.fullMode = false</code> from your <code>gradle.properties</code>.</li> </ul> <p style="text-align: left;"> If you are using reflection in your code base, then add <a href="https://developer.android.com/topic/performance/app-optimization/keep-rules-overview#where-to-add-rules" target="_blank">Keep rules</a> to prevent R8 from optimizing those parts of the code. Make sure to scope the keep rules narrowly to get the maximum optimization. </p> <p style="text-align: left;">To get the maximum optimization, make sure to follow these best practices in your keep rule file.</p> <ul style="text-align: left;"> <li>Remove global options like <code>-dontoptimize</code>, <code>-dontshrink</code>, and <code>-dontobfuscate</code> that prevent R8 from optimizing the entire codebase&nbsp;</li> <li>Remove keep rules that prevent optimizing Android components like Activity, Services, Views or Broadcast receivers.</li> <li>Refine the broad package wide keep rules to target only specific classes or methods.</li> </ul> <p style="text-align: left;">To see more best practices, view our <a href="https://developer.android.com/topic/performance/app-optimization/keep-rules-best-practices" target="_blank">keep rules documentation</a>.</p> <h3 style="text-align: left;">Library Developer R8 Best Practices</h3> <p>If you are a library developer, strictly place the rules your consumers need into your <code>consumer-rules</code> file, and keep your library's internal protection rules in your <code>proguard-rules.pro</code> file. For more information on how to optimize libraries, see <a href="https://developer.android.com/topic/performance/app-optimization/library-optimization" target="_blank">Optimization for library authors</a>.</p> <h3 style="text-align: left;">R8 Configuration Analyzer</h3> <p>To audit your R8 optimization, use the <b><a href="http://developer.android.com/r8-analyzer" target="_blank">Configuration Analyzer</a></b>. Configuration analyzer shows the current state of optimization with Obfuscation, Optimization, and Shrinking scores. With configuration analyzer, you can also understand how many classes, methods or fields are prevented from optimization by each keep rule. Refine these broad package wide keep rules to unlock the maximum optimization.</p> <p>Using configuration analyzer, you can also identify keep rules that are subsuming other keep rules, redundant keep rules and unused keep rules.</p> </div> <div class="separator" style="clear: both; text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib0dTmk8w7EYsDiV0Ufd8CAnpWz36-ZDC_gCGFkS_0CGz0axCxOy3RBxuaOoUbR4kzaeFBXryfSR2rkxRsmTXNrPtuJw8n1DTiZiKDqHjv3AaEXteE9TKV3QxYtwCztvY-8a0GpBlOZhVV1p0ftgdxeiKGGnO3dLu_IOt-TB_7j-ZnbR2jSr_CNYzh-bc/s2048/pic2-r8-config-analyzer.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"> <img border="0" data-original-height="1156" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib0dTmk8w7EYsDiV0Ufd8CAnpWz36-ZDC_gCGFkS_0CGz0axCxOy3RBxuaOoUbR4kzaeFBXryfSR2rkxRsmTXNrPtuJw8n1DTiZiKDqHjv3AaEXteE9TKV3QxYtwCztvY-8a0GpBlOZhVV1p0ftgdxeiKGGnO3dLu_IOt-TB_7j-ZnbR2jSr_CNYzh-bc/s16000/pic2-r8-config-analyzer.png" /> </a> </div> <div style="text-align: center;"> <i>The Configuration Analyzer shows the current state of optimization with Obfuscation, Optimization, and Shrinking scores.</i> </div> <div> <h4 style="text-align: left;"><span style="font-size: large;">R8 Agent Skill&nbsp;</span></h4> <p style="text-align: left;">You can also leverage the <b><a href="https://github.com/android/skills/tree/main/performance/r8-analyzer" target="_blank">R8 Agent Skill</a></b> with Android Studio agent or other AI tools to resolve misconfigurations and refine your rules resulting in improved app performance. <i>(Insights from AI-driven skills will require technical verification)</i></p> </div> <h3 id="Optimize" style="text-align: left;">Optimize image loading</h3> <div> <p>Bitmaps are usually the largest common objects residing in your app's memory. They represent the final stage of the image loading process where compressed files, like JPEGs or PNGs, are decoded into raw pixel data for display. This means a tiny 100KB compressed image can balloon into several megabytes of RAM because memory consumption is determined by the image's pixel dimensions and color depth. Since bitmap operations are frequently on the critical path to drawing frames, unoptimized images cause severe memory bloat and UI jank.</p> <p>Google recommends leveraging image loading libraries <b><a href="https://github.com/coil-kt/coil" target="_blank">Coil</a></b> for Kotlin-first projects, particularly when developing with Jetpack Compose and <b><a href="https://github.com/bumptech/glide" target="_blank">Glide</a></b> for Java-based applications.</p> <h4 style="text-align: left;"><span style="font-size: large;">Adopt these five best practices</span></h4> <ol style="text-align: left;"> <li><b>Downsample images:</b> If you’re loading bitmaps manually, avoid loading a massive image into a tiny thumbnail view; use <a href="https://developer.android.com/topic/performance/graphics/load-bitmap" target="_blank">inSampleSize</a> to load a smaller version. Glide and Coil downsamples images by default and you can configure this downsample strategy using <a href="https://bumptech.github.io/glide/javadocs/470/com/bumptech/glide/load/resource/bitmap/DownsampleStrategy.html" target="_blank">DownsampleStrategy</a> and <a href="https://coil-kt.github.io/coil/image_loaders/" target="_blank">ImageLoader</a> respectively.</li> <li><b>Cropping:</b> Avoid embedding padding directly into an image file for letterboxing purposes (e.g., creating a transparent border to expand an image dimensions). Rather than baking in these borders, utilize <a href="https://developer.android.com/reference/android/graphics/drawable/InsetDrawable" target="_blank">InsetDrawable</a> or apply padding directly within the View or Composable containing the bitmap.</li> <li><b>Config:</b> Balance memory and quality by choosing the right pixel format. Use <code>RGB_565</code> when transparency isn't needed, which uses half the memory of the default <code>ARGB_8888</code> format. In Glide you can configure this by using <a href="https://bumptech.github.io/glide/javadocs/470/com/bumptech/glide/load/DecodeFormat.html" target="_blank">DecodeFormat</a> and in Coil you can use <a href="https://coil-kt.github.io/coil/api/coil-core/coil3.request/-image-request/" target="_blank">bitmapConfig</a> property.</li> <li><b>Prioritize vector drawables:</b> For basic geometric assets, leverage <a href="https://developer.android.com/reference/android/graphics/drawable/ShapeDrawable" target="_blank">ShapeDrawable</a> as a lightweight alternative to decoding rasterized bitmaps. By defining these assets once via XML, you ensure they scale seamlessly across all display densities while effectively eliminating resource-driven memory bloat.</li> <li><b>Reuse:</b> If your application manages Bitmaps manually then to minimize memory churn, when a bitmap is no longer required, the app should call <code>bitmap.recycle()</code> and immediately discard the Bitmap reference. If you use an image loading library like Glide or Coil, return the bitmap to the library’s managed pool. By providing an existing buffer for future memory needs, the pool effectively avoids the overhead of new allocations.</li> </ol> <p style="text-align: left;">Check out our documentation on <a href="https://developer.android.com/develop/ui/compose/graphics/images/optimization" target="_blank">Optimizing performance for images</a> to learn more.</p> <h4 style="text-align: left;"><span style="font-size: large;">Android Studio tooling</span></h4> <p style="text-align: left;">You can also eliminate redundant bitmaps using Android Studio Narwhal 4. Here is how to hunt them down in five simple steps:</p> <ol style="text-align: left;"> <li>Open the <b>Profiler</b> tab in Android Studio</li> <li>Click <b>Heap Dump</b> (or "Analyze Memory Usage") and hit record to take a snapshot of your app’s current memory state.</li> <li>Scan the analysis results for the <b>yellow warning triangle</b> ⚠️, which Android Studio uses to flag duplicate bitmaps being stored multiple times. Alternatively, navigate to the profiler header, choose "Filter by:" and pick the "Duplicate Bitmaps" setting.</li> <li>Click on any flagged entry to open the <b>Bitmap Preview</b> pane, allowing you to see exactly which image is the repeat offender.</li> <li>Use that visual confirmation to track down the redundant loading logic in your code and implement a better caching strategy.</li> </ol> </div> <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDJ6djtozFY7DzrGB-EN8ajLVueF9MdLd4mod4jhtO8YwCzU7ObOwQ2w0Bap5A5NHJ7KVnXIRQqhW8cTdcFhMJPw5FIW1WU7D_Mwm-UC9Fsdr-MOn62xijpjKcS0NeUBnO957jmogGEISNQgeZQk3BVvUWK4BknTjLiuK2TbWCqwO3uTLkjkFhLwJre7w/s2379/pic3-IO26_113_TSV%20-dup-bitmaps-cropped.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1162" data-original-width="2379" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDJ6djtozFY7DzrGB-EN8ajLVueF9MdLd4mod4jhtO8YwCzU7ObOwQ2w0Bap5A5NHJ7KVnXIRQqhW8cTdcFhMJPw5FIW1WU7D_Mwm-UC9Fsdr-MOn62xijpjKcS0NeUBnO957jmogGEISNQgeZQk3BVvUWK4BknTjLiuK2TbWCqwO3uTLkjkFhLwJre7w/s16000/pic3-IO26_113_TSV%20-dup-bitmaps-cropped.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;"><i>Look for the yellow warning triangle ⚠️ in heap dumps when using the Android Studio Profiler.</i></div> <h3 id="Detect" style="text-align: left;">Detect and fix memory leaks with Android Studio</h3> <p style="text-align: left;">Memory leaks in Android occur when your code holds onto an object's reference long after its lifecycle has ended. This prevents the Garbage Collector (GC) from reclaiming that memory, eventually leading to sluggish performance or OutOfMemoryError (OOM).</p> <p style="text-align: left;">Android Studio Panda 3 features a dedicated&nbsp;<a href="https://square.github.io/leakcanary/" target="_blank">LeakCanary</a>&nbsp;profiler task, allowing developers to analyze real-time memory leaks and map traces within the IDE.</p> <p style="text-align: left;">The LeakCanary profiler task in Android Studio actively moves the memory leak analysis from your device to your development machine, resulting in a significant performance boost during the leak analysis phase as compared to on-device leak analysis.</p> <div class="separator" style="clear: both; text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKBixtkwy1hzwA6mikjRX_6vBJ9OQ_RCYdF94HUF8kOLYzQoQrPMLh_6h9u6EGeLzgFc8yjxg3_8zlqWIDCvKa1py5gyxDXasl8JLPDHSEgPpzPyYqzcme69rRKtfIlhMtyNRWXutGXNy-4WcefhSTBhqBgobK678fqvNqL5peOz1UD6ouunLaKPmJCw0/s2048/pic4-android-studio-leaks.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"> <img border="0" data-original-height="975" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKBixtkwy1hzwA6mikjRX_6vBJ9OQ_RCYdF94HUF8kOLYzQoQrPMLh_6h9u6EGeLzgFc8yjxg3_8zlqWIDCvKa1py5gyxDXasl8JLPDHSEgPpzPyYqzcme69rRKtfIlhMtyNRWXutGXNy-4WcefhSTBhqBgobK678fqvNqL5peOz1UD6ouunLaKPmJCw0/s16000/pic4-android-studio-leaks.png" /> </a> </div> <div style="text-align: center;"> <i>LeakCanary memory leak analysis contextualized with <b>Go to declaration</b> for debugging</i> </div> <p style="text-align: left;">Additionally, the leak analysis is now contextualized within the IDE and fully integrated with your source code, providing features like go to declaration and other helpful code connections that drastically reduce the friction and time required to investigate and fix memory leaks.</p> <div> <h4 style="text-align: left;"><span style="font-size: large;">Examples of common memory leaks&nbsp;</span></h4> <p style="text-align: left;">Memory leaks occur when an object persists in memory beyond its intended lifespan. This typically happens due to:</p> <ul style="text-align: left;"> <li>Retaining references to Fragments, Activities, or Views that are no longer in use.</li> <li>Mismanaging Context references.</li> <li>Failing to properly unregister observers, listeners, and receivers.</li> <li>Creating static references to objects that are bound to components with shorter lifecycles.</li> </ul> <p style="text-align: left;">Here are a few example scenarios:</p> <div align="left" dir="ltr" style="margin-left: 0pt;"> <table style="border-collapse: collapse; border-color: currentcolor; border-image: initial; border-style: none; border-width: medium; border: none; max-width: 100%; table-layout: auto; width: auto;"> <colgroup> <col style="width: 15%;"></col> <col style="width: 42.5%;"></col> <col style="width: 42.5%;"></col> </colgroup> <tbody> <tr style="height: auto;"> <td style="background-color: #efefef; border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Scenario</span></p> </td> <td style="background-color: #efefef; border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Compose-based example</span></p> </td> <td style="background-color: #efefef; border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">View-based example</span></p> </td> </tr> <tr style="height: auto;"> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: 400;">Leaking Context</span></p> </td> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin-bottom: 6pt;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Example:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Passing LocalContext.current to a ViewModel</span></p> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Fix:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Keep <code style="font-family: &quot;Roboto Mono&quot;, monospace;">Context</code> dependent logic within the UI layer. For non-UI layers, refactor to use <a href="https://developer.android.com/training/dependency-injection" style="color: #1155cc; text-decoration: underline;">dependency injection</a> or observe UI state using <a href="https://developer.android.com/kotlin/flow" style="color: #1155cc; text-decoration: underline;">Kotlin flow</a>.</span></p> </td> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin-bottom: 6pt;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Example:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Storing an <code style="font-family: &quot;Roboto Mono&quot;, monospace;">Activity</code> in a companion object or static variable.</span></p> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Fix:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Don’t hold static references to UI components. Refactor to use <a href="https://developer.android.com/training/dependency-injection" style="color: #1155cc; text-decoration: underline;">dependency injection</a> or observe UI state using <a href="https://developer.android.com/kotlin/flow" style="color: #1155cc; text-decoration: underline;">Kotlin flow</a>.</span></p> </td> </tr> <tr style="height: auto;"> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: 400;">Leaking Listeners</span></p> </td> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin-bottom: 6pt;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Example:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Using <code style="font-family: &quot;Roboto Mono&quot;, monospace;">DisposableEffect</code> to start a listener but leaving <code style="font-family: &quot;Roboto Mono&quot;, monospace;">onDispose</code> empty.</span></p> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Fix:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Perform the unregistration and <a href="https://developer.android.com/develop/ui/compose/side-effects#disposableeffect" style="color: #1155cc; text-decoration: underline;">cleanup logic</a> inside the <code style="font-family: &quot;Roboto Mono&quot;, monospace;">onDispose</code> block.</span></p> </td> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin-bottom: 6pt;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Example:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Registering for SensorManager updates and forgetting to unregister.</span></p> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Fix:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Manually call <code style="font-family: &quot;Roboto Mono&quot;, monospace;">unregisterListener()</code> in <code style="font-family: &quot;Roboto Mono&quot;, monospace;">onStop()</code> or <code style="font-family: &quot;Roboto Mono&quot;, monospace;">onDestroy()</code> lifecycle.</span></p> </td> </tr> <tr style="height: auto;"> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: 400;">Leaking Views</span></p> </td> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin-bottom: 6pt;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Example:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Holding a reference to a legacy <code style="font-family: &quot;Roboto Mono&quot;, monospace;">View</code> inside an <code style="font-family: &quot;Roboto Mono&quot;, monospace;">AndroidView</code> without a release strategy.</span></p> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Fix:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Use the <code style="font-family: &quot;Roboto Mono&quot;, monospace;">release</code> block of the <code style="font-family: &quot;Roboto Mono&quot;, monospace;">AndroidView</code> composable to clean up the legacy <code style="font-family: &quot;Roboto Mono&quot;, monospace;">View</code>.</span></p> </td> <td style="border: 0.75pt solid rgb(31, 31, 31); padding: 8px; vertical-align: top;"> <p dir="ltr" style="line-height: 1.2; margin-bottom: 6pt;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Example:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Keeping a reference to a view binding object after the <code style="font-family: &quot;Roboto Mono&quot;, monospace;">Fragment</code> is destroyed.</span></p> <p dir="ltr" style="line-height: 1.2; margin: 0px;"><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt; font-weight: bold;">Fix:</span><br /><span face="'Google Sans',sans-serif" style="color: black; font-size: 11pt;">Set the binding variable to <code>null</code> inside the <code style="font-family: &quot;Roboto Mono&quot;, monospace;">onDestroyView</code>() lifecycle method.</span></p> </td> </tr> </tbody> </table> </div> </div> <h3 id="Trim" style="text-align: left;">Trim memory when app leaves visible state</h3> <p>Android can reclaim memory from your app or stop your app entirely if necessary to free up memory for critical tasks, as explained in <a href="https://developer.android.com/topic/performance/memory-overview" target="_blank">Overview of memory management</a>. Android will usually reclaim memory from your app when it’s not visible to the user, such as by discarding some of your app’s code and data pages in memory or compressing your heap allocations. When the user resumes your app and your app tries to access some memory that’s been reclaimed, the OS will swap that memory back in on demand. This swapping behavior can be slow, and cause unexpected jank or stutters in your app.</p> <p>If you leave it to the OS to decide what memory to reclaim from your app, you may find that the OS reclaimed memory that you’ll need shortly after resuming your app. Instead, your app can voluntarily discard memory allocations that it can regenerate later, on demand and at a low cost. To do so, you can implement the <code>ComponentCallbacks2</code> interface. You can implement <code>onTrimMemory</code> in your <code>Activity</code>, <code>Fragment</code>, <code>Service</code>, or even your custom <code>Application</code> class. Using it in the <code>Application</code> class is highly effective for global cache management.</p> <p>The provided <a href="https://developer.android.com/reference/android/content/ComponentCallbacks2#onTrimMemory(int)" target="_blank">onTrimMemory()</a> callback method notifies your app of lifecycle or memory-related events that present a good opportunity for your app to voluntarily reduce its memory usage.</p> <p>In terms of memory lifecycle management, your implementation should focus <b>exclusively</b> on <code>TRIM_MEMORY_UI_HIDDEN</code> and <code>TRIM_MEMORY_BACKGROUND</code>. Since Android 14, the system has ceased delivering notifications for other legacy constants, which were formally deprecated in Android 15.</p> <p><code>TRIM_MEMORY_UI_HIDDEN</code>: This signal indicates that your application's UI has transitioned out of the user's view. This provides an opportunity to release substantial memory allocations tied strictly to the interface—such as Bitmaps, video playback buffers, or complex animation resources.</p> <p><code>TRIM_MEMORY_BACKGROUND</code>: At this level, your process is residing in the background and is now a candidate for termination to satisfy the system's global memory needs. To extend the duration your process remains in the cached state, and reduce the number of app cold starts, you should aggressively release any resources that can be easily reconstructed once the user resumes their session.</p> <pre style="background-color: whitesmoke; border-radius: 4px; box-sizing: border-box; color: #333333; display: inline-block; font-family: &quot;Roboto Mono&quot;, monospace; font-size: 10pt; line-height: 1.5; margin: 1em 0px; max-width: 100%; min-width: 60%; overflow-x: auto; padding: 12px;"><code>import android.content.ComponentCallbacks2 // Other import statements. class MainActivity : AppCompatActivity(), ComponentCallbacks2 { /** * Release memory when the UI becomes hidden or when system resources become low. * @param level the memory-related event that is raised. */ override fun onTrimMemory(level: Int) { if (level &gt;= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Release memory related to UI elements, such as bitmap caches. } if (level &gt;= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { // Release memory related to background processing, such as by // closing a database connection. } } }</code></pre> <p>Note: The <code>onTrimMemory</code> integration may depend on SDK support. For instance, certain games rely on their game engine to enable this capability. Please check out the <a href="https://developer.android.com/games/optimize/memory-allocation" target="_blank">game memory optimization documents</a>.</p> <h3 id="Advanced" style="text-align: left;">Advanced memory observability with ProfilingManager</h3> <p style="text-align: left;">To catch and diagnose memory issues in the field that cannot be reproduced locally, you should leverage the <b>ProfilingManager API</b>. Introduced in Android 15, this advanced observability API allows you to programmatically collect real-user Perfetto profiles.</p> <p style="text-align: left;">For teams that lack a dedicated infrastructure to manage and host performance artifacts, Crashlytics is exploring a specialized solution to streamline this workflow. They are inviting developers to <a href="https://docs.google.com/forms/d/e/1FAIpQLSe299a_zSNDfa164z7yyqoDjS05ZDRN86bAQKajuAOFEQ4G-w/viewform" target="_blank">provide feedback</a>.</p> <p style="text-align: left;"><b>Android 17 introduces new event-driven triggers</b>, most notably <code>TRIGGER_TYPE_OOM</code> and <code>TRIGGER_TYPE_ANOMALY</code>:</p> <ul style="text-align: left;"> <li>The <b>OOM trigger</b> automatically collects a Java heap dump at the exact moment an OutOfMemoryError crash occurs, providing precise allocation states. A collected OOM profile is provided the next time the app starts and registers the <code>registerForAllProfilingResults</code> callback.</li> <li>The <b>Anomaly trigger</b> detects severe performance issues, such as excessive binder spam or breached memory thresholds. The memory anomaly delivers a heap dump just prior to the system terminating the app.</li> </ul> <pre style="background-color: whitesmoke; border-radius: 4px; box-sizing: border-box; color: #333333; display: inline-block; font-family: &quot;Roboto Mono&quot;, monospace; font-size: 10pt; line-height: 1.5; margin: 1em 0px; max-width: 100%; min-width: 60%; overflow-x: auto; padding: 12px;"><code> val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java) val triggers = ArrayList<profilingtrigger>() triggers.add(ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_ANOMALY)) val mainExecutor: Executor = Executors.newSingleThreadExecutor() val resultCallback = Consumer<profilingresult> { profilingResult -&gt; if (profilingResult.errorCode != ProfilingResult.ERROR_NONE) { // upload profile result to server for further analysis setupProfileUploadWorker(profilingResult.resultFilePath) } profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback) profilingManager.addProfilingTriggers(triggers)</profilingresult></profilingtrigger></code></pre> <p style="text-align: left;"> Once you’ve collected the heap dump, you can download the profile from the server, or locally via adb pull and drag and drop the file into the <a href="http://ui.perfetto.dev" target="_blank">Perfetto UI</a>. To streamline your memory debugging workflow, use the <a href="https://perfetto.dev/docs/visualization/heap-dump-explorer" target="_blank">Heap Dump Explorer</a>, this is the new default view for heap dumps in Perfetto UI. This tool provides an intuitive interface for inspecting Java heap dumps, allowing you to visualize object allocation hierarchies, compute retained memory sizes, and identify the shortest path from garbage collection root. By leveraging the Heap Dump Explorer, you can rapidly pinpoint memory leaks, bloated retained objects such as excessive bitmap allocations, and analyze heap object allocations all in one place. </p> <div class="separator" style="clear: both; text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhobASfyUbXdAYD_MOjREv7RUhCwoNJ9sB4QDSImRfA0UrALJqwQ2ovgAF7YRt3f26UeZoIQa-yDxiSDO84gxv1XkQ8acf8E795-IgAe4tl8AM_7m7nSEuj7t_rhtpgM3f-76_lEh-k7Rltku79-VCuIDN_2Q9DRjJyouCKbxg4pDXHV2yey7V8WlG2jQM/s2048/pic5-perfettoheapdump-analyzer.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"> <img border="0" data-original-height="1039" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhobASfyUbXdAYD_MOjREv7RUhCwoNJ9sB4QDSImRfA0UrALJqwQ2ovgAF7YRt3f26UeZoIQa-yDxiSDO84gxv1XkQ8acf8E795-IgAe4tl8AM_7m7nSEuj7t_rhtpgM3f-76_lEh-k7Rltku79-VCuIDN_2Q9DRjJyouCKbxg4pDXHV2yey7V8WlG2jQM/s16000/pic5-perfettoheapdump-analyzer.png" /> </a> </div> <div style="text-align: center;"> <i>Use the <a href="https://perfetto.dev/docs/visualization/heap-dump-explorer">Heap Dump Explorer</a>’s embedded flamegraph to visually inspect and navigate through objects with the highest heap allocations.</i> </div> <h3 style="text-align: left;">Conclusion</h3> <p>Optimizing bytecode with R8, adopting image loading best practices, and resolving memory leaks are critical steps toward delivering a high-quality user experience while managing resources effectively under pressure. Adopting these proactive measures helps maintain app stability and performance, preventing unexpected terminations while safeguarding user context. To further your performance expertise, explore our revised <a href="https://developer.android.com/topic/performance/memory" target="_blank">memory guidance</a>.</p>