# R8

R8 is an Android app optimizer that removes unused code and resources, rewrites code for efficiency, and reduces app size and runtime overhead.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Obfuscation Fundamentals: Applying ProGuard and R8 Protections to Android Code

DevFeed: [Obfuscation Fundamentals: Applying ProGuard and R8 Protections to Android Code](<https://devfeed.tech/articles/obfuscation-32342.md>)

Original publisher: [Read original article](<https://dustn.dev/page/presentations/2019-07-24-obfuscation-fundamentals/>)

Author: dustin@dustn.dev (Dustin Summers)

Published: 2026-09-17T04:13:15.404035Z

Content type: tutorial

Language: en

Sources: [Dustin Summers](<https://devfeed.tech/sources/dustin-summers.md>)

Topics: [obfuscation](<https://devfeed.tech/topics/obfuscation.md>), [Android](<https://devfeed.tech/topics/android.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [meetup](<https://devfeed.tech/tags/meetup.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [proguard](<https://devfeed.tech/tags/proguard.md>), [r8](<https://devfeed.tech/tags/r8.md>), [video](<https://devfeed.tech/tags/video.md>)

### AI overview

A presentation introducing obfuscation with ProGuard and R8, focused on applying protections to Android code. It explains how to diagnose the code entering and leaving these build tools.

### Source excerpt

This presentation was given at a MeetUp in DC. It corresponds to this series of blog posts, which is the first in a series to teach about Obfuscation/ProGuard/R8, and will primarily be centered around applying protections to Android Code. Tools such as R8 and ProGuard are available, but to many they are a black box that code goes into and stuff comes out. The following will demystify the black box, and teach developers how to properly diagnose the code going into and coming out of these build tools.

## Tinder cuts app cold starts by 47% with new R8 Configuration Analyzer

DevFeed: [Tinder cuts app cold starts by 47% with new R8 Configuration Analyzer](<https://devfeed.tech/articles/tinder-cuts-app-cold-starts-by-47-with-new-r8-configuration-analyzer-4241.md>)

Original publisher: [Read original article](<https://android-developers.googleblog.com/2026/08/tinder-app-cold-start-r8-configuration-analyzer.html>)

Author: Android Developers (noreply@blogger.com)

Published: 2026-08-18T18:00:00Z

Content type: article

Language: en

Sources: [Android Developers Blog](<https://devfeed.tech/sources/android-developers-blog.md>), [Android Developers Blog](<https://devfeed.tech/sources/android-developers-blog-2.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Android](<https://devfeed.tech/topics/android.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [configuration](<https://devfeed.tech/topics/configuration.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [agentic](<https://devfeed.tech/tags/agentic.md>), [android](<https://devfeed.tech/tags/android.md>), [development](<https://devfeed.tech/tags/development.md>), [errors](<https://devfeed.tech/tags/errors.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>), [startup](<https://devfeed.tech/tags/startup.md>), [time](<https://devfeed.tech/tags/time.md>)

### AI overview

The article describes how Tinder used the R8 Configuration Analyzer to identify and remove keep-rule blockers in its Android application. The effort reduced cold-start time by 47%, app download size by 28.98% to 61.5 MB, and user-perceived ANRs by 28%.

### Source excerpt

Posted by Ajesh R Pai, Developer Relations Engineer, Ulises Uriel Verduzco Diaz, Software Engineer, Tinder, and Tracy Agyemang, Product Marketing Manager Tinder is on a mission to power and inspire real connections by making meeting easy and fun for every new generation of singles. However, as their Android application codebase grew in size, so did its complexity. Prior to their latest optimization efforts, approximately 70% of the application was not optimized, carrying 17 dex files,including three dedicated just to startup. Although they had enabled R8, much of its optimization potential was blocked due to keep rules, and the team was unable to identify which specific rules were preventing optimization. To reduce startup time and decrease user-perceived Application Not Responding (ANR) errors, Tinder turned to the new R8 Configuration Analyzer to tackle these challenges. By utilizing the R8 Configuration Analyzer, Tinder successfully identified and removed unintentional optimization blockers. The results were immediate and impactful: Tinder achieved a 47% reduction in app cold starts, shrank their app download size by 28.98% (down to 61.5 MB), and reduced user-perceived ANRs by 28%. Configuration analyzer The R8 Configuration Analyzer shows R8 optimization by tracking shrinking, optimization, and obfuscation scores to show available refinement areas. It shows the broad, redundant, or obsolete keep rules, including those from external libraries so that you can analyse the keep rule impact and refine the keep rules. Key metrics shown in Configuration Analyzer include: Shrinking Score: Code percentage available for R8 shrinking. Optimization Score: Code percentage open to optimization (for example, method inlining, horizontal class merging). Obfuscation Score: Percentage of classes, methods and fields that can be renamed by R8 to decrease size. Use the analyzer to audit keep rules and their impacts: Find broad rules: Narrow the scope of package-wide rules that restri

## Tinder cuts app cold starts by 47% with new R8 Configuration Analyzer

DevFeed: [Tinder cuts app cold starts by 47% with new R8 Configuration Analyzer](<https://devfeed.tech/articles/tinder-cuts-app-cold-starts-by-47-with-new-r8-configuration-analyzer-22698.md>)

Original publisher: [Read original article](<http://android-developers.googleblog.com/2026/08/tinder-app-cold-start-r8-configuration-analyzer.html>)

Author: Android Developers (noreply@blogger.com)

Published: 2026-08-18T18:00:00Z

Content type: article

Language: en

Sources: [Android Developers Blog](<https://devfeed.tech/sources/android-developers-blog-3.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Android](<https://devfeed.tech/topics/android.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [configuration](<https://devfeed.tech/topics/configuration.md>), [audit](<https://devfeed.tech/topics/audit.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [anr](<https://devfeed.tech/tags/anr.md>), [audit](<https://devfeed.tech/tags/audit.md>), [configuration](<https://devfeed.tech/tags/configuration.md>), [metrics](<https://devfeed.tech/tags/metrics.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This developer case study explains how Tinder used the R8 Configuration Analyzer to identify and remove keep-rule blockers in its Android application. The reported results were a 47% reduction in cold-start time, a 28.98% reduction in download size to 61.5 MB, and a 28% reduction in user-perceived ANRs. The article also describes analyzer metrics for shrinking, optimization, and obfuscation, along with an R8 Analyzer skill for agentic development workflows.

### Source excerpt

Posted by Ajesh R Pai, Developer Relations Engineer, Ulises Uriel Verduzco Diaz, Software Engineer, Tinder, and Tracy Agyemang, Product Marketing Manager Tinder is on a mission to power and inspire real connections by making meeting easy and fun for every new generation of singles. However, as their Android application codebase grew in size, so did its complexity. Prior to their latest optimization efforts, approximately 70% of the application was not optimized, carrying 17 dex files,including three dedicated just to startup. Although they had enabled R8, much of its optimization potential was blocked due to keep rules, and the team was unable to identify which specific rules were preventing optimization. To reduce startup time and decrease user-perceived Application Not Responding (ANR) errors, Tinder turned to the new R8 Configuration Analyzer to tackle these challenges. By utilizing the R8 Configuration Analyzer, Tinder successfully identified and removed unintentional optimization blockers. The results were immediate and impactful: Tinder achieved a 47% reduction in app cold starts, shrank their app download size by 28.98% (down to 61.5 MB), and reduced user-perceived ANRs by 28%. Configuration analyzer The R8 Configuration Analyzer shows R8 optimization by tracking shrinking, optimization, and obfuscation scores to show available refinement areas. It shows the broad, redundant, or obsolete keep rules, including those from external libraries so that you can analyse the keep rule impact and refine the keep rules. Key metrics shown in Configuration Analyzer include: Shrinking Score: Code percentage available for R8 shrinking. Optimization Score: Code percentage open to optimization (for example, method inlining, horizontal class merging). Obfuscation Score: Percentage of classes, methods and fields that can be renamed by R8 to decrease size. Use the analyzer to audit keep rules and their impacts: Find broad rules: Narrow the scope of package-wide rules that restri

## The Hidden Costs of DIY Android App Security | Guardsquare

DevFeed: [The Hidden Costs of DIY Android App Security | Guardsquare](<https://devfeed.tech/articles/the-hidden-costs-of-diy-android-app-security-guardsquare-26305.md>)

Original publisher: [Read original article](<https://www.guardsquare.com/blog/diy-android-app-security-hidden-costs>)

Author: Michael Olechna - Product Marketing Manager

Published: 2026-07-28T13:00:55Z

Content type: opinion

Language: en

Sources: [Guardsquare Blog](<https://devfeed.tech/sources/guardsquare-blog.md>)

Topics: [Security](<https://devfeed.tech/topics/security.md>), [Android](<https://devfeed.tech/topics/android.md>), [Mobile](<https://devfeed.tech/topics/mobile.md>), [obfuscation](<https://devfeed.tech/topics/obfuscation.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Open Source](<https://devfeed.tech/topics/open-source.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [dexguard](<https://devfeed.tech/tags/dexguard.md>), [mobile](<https://devfeed.tech/tags/mobile.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [open-source](<https://devfeed.tech/tags/open-source.md>), [protection](<https://devfeed.tech/tags/protection.md>), [r8](<https://devfeed.tech/tags/r8.md>), [security](<https://devfeed.tech/tags/security.md>), [thought-leadership](<https://devfeed.tech/tags/thought-leadership.md>), [threat-monitoring](<https://devfeed.tech/tags/threat-monitoring.md>)

### AI overview

The article argues that DIY Android app security built around open-source tools can leave important protection gaps. It explains that R8 helps compile and optimize Android applications but is not a complete security solution, lacking capabilities such as string encryption, API endpoint security, and control-flow obfuscation.

### Source excerpt

The DIY temptation to build with open-source is strong for mobile app developers. After all, their job is to build, secure, and design new applications, features, and architectures that benefit the users of their apps.

## How R8 made Kotlin Coroutines on Android 2x faster

DevFeed: [How R8 made Kotlin Coroutines on Android 2x faster](<https://devfeed.tech/articles/how-r8-made-kotlin-coroutines-on-android-2x-faster-22684.md>)

Original publisher: [Read original article](<http://android-developers.googleblog.com/2026/07/how-r8-made-kotlin-coroutines-2x-faster.html>)

Author: Android Developers (noreply@blogger.com)

Published: 2026-07-27T13:00:00Z

Content type: article

Language: en

Sources: [Android Developers Blog](<https://devfeed.tech/sources/android-developers-blog-3.md>)

Topics: [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Android](<https://devfeed.tech/topics/android.md>), [Compose](<https://devfeed.tech/topics/compose.md>), [Programming](<https://devfeed.tech/topics/programming.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-gradle-plugin](<https://devfeed.tech/tags/android-gradle-plugin.md>), [app-performance](<https://devfeed.tech/tags/app-performance.md>), [atomic](<https://devfeed.tech/tags/atomic.md>), [compose](<https://devfeed.tech/tags/compose.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [jetpack-compose](<https://devfeed.tech/tags/jetpack-compose.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [perfetto](<https://devfeed.tech/tags/perfetto.md>), [performance](<https://devfeed.tech/tags/performance.md>), [programming](<https://devfeed.tech/tags/programming.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This article explains how R8 in AGP 9.2.0 optimizes Atomic*FieldUpdater calls into Unsafe variants, improving common operations by 2x to 4x. The optimization particularly benefits kotlinx.atomicfu and can make launching and cancelling Kotlin coroutines up to 2x faster. It also describes how coroutine overhead affected Jetpack Compose performance and how ART method traces helped identify bottlenecks.

### Source excerpt

Posted by Andrei Shikov, Senior Software Engineer, Android Toolkit and Jonathan Starup, Software Engineer, R8 Team Starting from AGP 9.2.0, R8 optimizes most Atomic*FieldUpdater calls into Unsafe variants that perform 2x to 4x better on common operations. This has a particularly large impact on the kotlinx.atomicfu library that implements atomics for kotlinx.coroutines, making launching and cancelling coroutines up to 2x faster. In order to get the benefits, update your AGP to 9.2.0 or above. With the majority of Android apps adopting Kotlin as their main language of choice, kotlinx.coroutines has become a de-facto standard for asynchronous programming. The library offers a well-designed and structured way of managing concurrent flows that is native to Kotlin. Jetpack Compose was no exception, adopting coroutines for managing pointer events, animations and other interactions. At the time of writing, most concurrent APIs in Compose call suspend functions under the hood and are launching and/or cancelling coroutines to handle updates. As the Compose team started to investigate performance, coroutines were discovered to be a bottleneck for many operations that happen outside of composition. As an example, 80% of the time spent on creating and updating Modifier.clickable was consumed by launching and cancelling internal coroutines that handled InteractionSource updates. Based on those observations, much of early performance work was focused on removing coroutines from the default path and delaying initialization until necessary. The cost of a coroutine The easiest way to analyze a function's internal behavior on Android is to capture an Android Runtime (ART) method trace. An ART method trace is a tool that records the execution flow of an app, showing exactly which methods are called, their order, and how much time is spent in each, allowing developers to identify performance bottlenecks. For an empty LaunchedEffect { } call, it would look something like this: LaunchedE

## How R8 made Kotlin Coroutines on Android 2x faster

DevFeed: [How R8 made Kotlin Coroutines on Android 2x faster](<https://devfeed.tech/articles/how-r8-made-kotlin-coroutines-on-android-2x-faster-4227.md>)

Original publisher: [Read original article](<https://android-developers.googleblog.com/2026/07/how-r8-made-kotlin-coroutines-2x-faster.html>)

Author: Android Developers (noreply@blogger.com)

Published: 2026-07-27T13:00:00Z

Content type: article

Language: en

Sources: [Android Developers Blog](<https://devfeed.tech/sources/android-developers-blog.md>), [Android Developers Blog](<https://devfeed.tech/sources/android-developers-blog-2.md>)

Topics: [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Android](<https://devfeed.tech/topics/android.md>), [Compose](<https://devfeed.tech/topics/compose.md>), [Programming](<https://devfeed.tech/topics/programming.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-gradle-plugin](<https://devfeed.tech/tags/android-gradle-plugin.md>), [app-performance](<https://devfeed.tech/tags/app-performance.md>), [atomic](<https://devfeed.tech/tags/atomic.md>), [compose](<https://devfeed.tech/tags/compose.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [performance](<https://devfeed.tech/tags/performance.md>), [programming](<https://devfeed.tech/tags/programming.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This article explains how R8 optimization in AGP 9.2.0 improves Kotlin coroutines performance on Android. By optimizing AtomicFieldUpdater calls, the change makes launching and cancelling coroutines up to twice as fast, addressing coroutine-related bottlenecks in Jetpack Compose and other Android operations.

### Source excerpt

Posted by Andrei Shikov, Senior Software Engineer, Android Toolkit and Jonathan Starup, Software Engineer, R8 Team Starting from AGP 9.2.0, R8 optimizes most Atomic*FieldUpdater calls into Unsafe variants that perform 2x to 4x better on common operations. This has a particularly large impact on the kotlinx.atomicfu library that implements atomics for kotlinx.coroutines, making launching and cancelling coroutines up to 2x faster. In order to get the benefits, update your AGP to 9.2.0 or above. With the majority of Android apps adopting Kotlin as their main language of choice, kotlinx.coroutines has become a de-facto standard for asynchronous programming. The library offers a well-designed and structured way of managing concurrent flows that is native to Kotlin. Jetpack Compose was no exception, adopting coroutines for managing pointer events, animations and other interactions. At the time of writing, most concurrent APIs in Compose call suspend functions under the hood and are launching and/or cancelling coroutines to handle updates. As the Compose team started to investigate performance, coroutines were discovered to be a bottleneck for many operations that happen outside of composition. As an example, 80% of the time spent on creating and updating Modifier.clickable was consumed by launching and cancelling internal coroutines that handled InteractionSource updates. Based on those observations, much of early performance work was focused on removing coroutines from the default path and delaying initialization until necessary. The cost of a coroutine The easiest way to analyze a function's internal behavior on Android is to capture an Android Runtime (ART) method trace. An ART method trace is a tool that records the execution flow of an app, showing exactly which methods are called, their order, and how much time is spent in each, allowing developers to identify performance bottlenecks. For an empty LaunchedEffect { } call, it would look something like this: LaunchedE

## Obfuscation Deep Dive: Enhancing R8 and ProGuard for Robust Android Code Protection

DevFeed: [Obfuscation Deep Dive: Enhancing R8 and ProGuard for Robust Android Code Protection](<https://devfeed.tech/articles/obfuscation-deep-dive-enhancing-r8-and-proguard-for-robust-android-code-protection-25958.md>)

Original publisher: [Read original article](<https://kirillr.medium.com/proguard-r8-obfuscation-dictionary-b4541a898eb8?source=rss-7a0a233f88a2------2>)

Author: Kirill Rozov

Published: 2025-05-19T07:40:40Z

Content type: tutorial

Language: en

Sources: [Stories by Kirill Rozov on Medium](<https://devfeed.tech/sources/stories-by-kirill-rozov-on-medium.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [obfuscation](<https://devfeed.tech/topics/obfuscation.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Reverse Engineering](<https://devfeed.tech/topics/reverse-engineering.md>), [Java](<https://devfeed.tech/topics/java.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [configuration](<https://devfeed.tech/topics/configuration.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [configuration](<https://devfeed.tech/tags/configuration.md>), [java](<https://devfeed.tech/tags/java.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [proguard](<https://devfeed.tech/tags/proguard.md>), [r8](<https://devfeed.tech/tags/r8.md>), [reverse-engineering](<https://devfeed.tech/tags/reverse-engineering.md>), [security](<https://devfeed.tech/tags/security.md>)

### AI overview

This tutorial explains how R8 and ProGuard obfuscate Android applications and why their default naming dictionaries can make reverse engineering easier. It presents custom dictionary configuration, Java reserved-keyword names, invalid Windows filename names, and per-build randomized dictionaries, while noting compatibility and testing risks.

### Source excerpt

Obfuscation is a crucial aspect of securing Android applications. While tools like R8 and ProGuard are commonly used, their default configurations primarily aim to reduce app size rather than fortify code against reverse engineering. This article delves into advanced obfuscation techniques to make reverse engineering harder. Understanding Obfuscation Obfuscation transforms readable code into a form that's difficult to interpret. For instance, UserManager might become a, and getUser() could be renamed to b(). R8 and ProGuard perform obfuscation alongside code shrinking and optimization. # R8/ProGuard default dictionary a b c ... z These tools use dictionaries to generate new names, typically starting with single letters (a to z) and progressing to combinations like aa, ab, etc. While this approach minimizes file size, it has drawbacks: Predictable Naming: Limited name variations make it easier to deduce original identifiers. Consistent Builds: Repeated builds produce identical obfuscated names, aiding pattern recognition. Simplified Reverse Engineering: Tools can exploit naming patterns across builds. To counter these issues, customizing the obfuscation dictionary is essential. Implementing Custom Dictionaries R8 and ProGuard allow the use of custom dictionaries via configuration files: # proguard-rules.txt # Add to R8/ProGuard config file -obfuscationdictionary obfuscation-dictionary.tx -classobfuscationdictionary class-dictionary.txt -packageobfuscationdictionary package-dictionary.txt By providing unique dictionaries, you can generate diverse and unpredictable obfuscated names. Advanced Dictionary StrategiesJava Reserved Keywords Using Java's reserved keywords (e.g., if, for, class) as obfuscated names can confuse decompilers, as these are invalid identifiers in source code but acceptable in bytecode. # Java Reserved Keywords dictionary do if for int new ... instanceof synchronized Example of deobfucated Java code with java reserved keywords dictionary package cla

## The curious case of a weird VerifyError crash

DevFeed: [The curious case of a weird VerifyError crash](<https://devfeed.tech/articles/the-curious-case-of-a-weird-verifyerror-crash-25583.md>)

Original publisher: [Read original article](<https://www.marcogomiero.com/posts/2025/bug-hunting-story/>)

Author: Marco Gomiero

Published: 2025-04-06T00:00:00Z

Content type: article

Language: en

Sources: [Posts on Marco Gomiero](<https://devfeed.tech/sources/posts-on-marco-gomiero.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [debugging](<https://devfeed.tech/topics/debugging.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Compose](<https://devfeed.tech/topics/compose.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-gradle-plugin](<https://devfeed.tech/tags/android-gradle-plugin.md>), [crash](<https://devfeed.tech/tags/crash.md>), [debugging](<https://devfeed.tech/tags/debugging.md>), [dependency](<https://devfeed.tech/tags/dependency.md>), [issue](<https://devfeed.tech/tags/issue.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

A journal-style debugging account of a VerifyError runtime crash in FeedFlow's Android release build after upgrading the Android Gradle Plugin to version 8.7. The investigation tests R8, Compose, Kotlin, and dependency combinations, then narrows the problem to code in the dependency graph involving date-string parsing.

### Source excerpt

This post can be considered as a journal entry. I had to clear my thoughts and vent off through writing after spending time debugging this issue. Maybe it will be helpful for future references or an example of the process to follow in such cases. The other day I was doing the usual dependency update routine of FeedFlow when I discovered a runtime crash that happened in the release version (so with R8 enabled) after updating the Android Gradle Plugin (AGP, in the rest of the article) to version 8.7.

## Optimizing Rectangle-Overlap Tests by Removing Conditional Branches

DevFeed: [Optimizing Rectangle-Overlap Tests by Removing Conditional Branches](<https://devfeed.tech/articles/down-a-rabbit-hole-25596.md>)

Original publisher: [Read original article](<https://www.romainguy.dev/posts/2024/down-a-rabbit-hole/>)

Author: Romain Guy

Published: 2024-05-18T00:00:00Z

Content type: tutorial

Language: en

Sources: [Posts on Romain Guy](<https://devfeed.tech/sources/posts-on-romain-guy.md>)

Topics: [Optimization](<https://devfeed.tech/topics/optimization.md>), [Code](<https://devfeed.tech/topics/code.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Benchmark](<https://devfeed.tech/topics/benchmark.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [assembly](<https://devfeed.tech/tags/assembly.md>), [benchmark](<https://devfeed.tech/tags/benchmark.md>), [code](<https://devfeed.tech/tags/code.md>), [developer](<https://devfeed.tech/tags/developer.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [performance](<https://devfeed.tech/tags/performance.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This article examines optimizing rectangle-overlap tests in Kotlin. It compares generated assembly, replaces logical operators with bitwise operators to remove conditional branches, and reports a 1.7x speedup in a benchmark on a Google Pixel 6.

### Source excerpt

I recently discussed an optimization that I worked on following Leland's successful nerd snipe. That, however, was not the end of it. He also needed to test for intersecting/overlapping rectangles. The most obvious way to achieve this is pretty straightforward: 1// A rectangle is defined by its left (l), top (t), 2// right (r), and bottom (b) coordinates 3data class Rect(val l: Int, val t: Int, val r: Int, val b: Int) { 4 fun overlaps(other: Rect) = 5 l < other.r && other.l < r && t < other.b && other.t < b 6} The source code is nice and tidy, but the generated assembly is less than ideal (as always, the code was optimized with R8 first):

## Crafting Android bytecode analysis tooling using a secret ingredient (Part 1)

DevFeed: [Crafting Android bytecode analysis tooling using a secret ingredient (Part 1)](<https://devfeed.tech/articles/crafting-android-bytecode-analysis-tooling-using-a-secret-ingredient-part-1-22597.md>)

Original publisher: [Read original article](<https://medium.com/bumble-tech/crafting-android-bytecode-analysis-tooling-using-a-secret-ingredient-part-1-13e2d5a65113?source=rss----6353b5325b1a---4>)

Author: Konstantin Zolotov

Published: 2024-02-09T11:50:19Z

Content type: tutorial

Language: en

Sources: [Bumble Tech](<https://devfeed.tech/sources/bumble-tech.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Tooling](<https://devfeed.tech/topics/tooling.md>), [APK](<https://devfeed.tech/topics/apk.md>), [obfuscation](<https://devfeed.tech/topics/obfuscation.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Java](<https://devfeed.tech/topics/java.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>)

Tags: [andriod-app-development](<https://devfeed.tech/tags/andriod-app-development.md>), [android](<https://devfeed.tech/tags/android.md>), [apk](<https://devfeed.tech/tags/apk.md>), [bytecode](<https://devfeed.tech/tags/bytecode.md>), [compilation](<https://devfeed.tech/tags/compilation.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [dagger](<https://devfeed.tech/tags/dagger.md>), [inlining](<https://devfeed.tech/tags/inlining.md>), [java](<https://devfeed.tech/tags/java.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>), [tooling](<https://devfeed.tech/tags/tooling.md>)

### AI overview

This tutorial introduces Android bytecode analysis through DEX inspection and a tool for examining how source-code changes affect compiled binaries. It explains the Android compilation pipeline from Java or Kotlin source through JVM class files and D8-generated DEX files, then describes R8 obfuscation and optimization, including source maps, tree-shaking, inlining, and outlining.

### Source excerpt

During the development process, we often focus on the source code but rarely inspect the compiled bytecode. This means we're missing out on a valuable source of information and data for analysis. How? Let's delve into Dex file inspection and build a tool that demonstrates how source code changes impact the compiled binary. Have you ever set R8 rules to obfuscate your app? Have you used an APK analyzer or a diffuse tool to understand how the code is compiled? Are you confident that debug code hasn't leaked into production? There's another potential pitfall: libraries may provide obfuscation rules (e.g., Gson) that merge with the ones in your project. This means third-party dependencies can alter configurations for the entire app. We often assume everything is fine and that we'll notice if something isn't right. But will we? Does this make you feel uneasy? Does it concern you? Because it certainly concerns me. Here, we'll attempt to enhance the situation and enable you to see precisely how your code changes impact the compiled binary. To better comprehend this, let's start with the code compilation process: It all begins with the Java and/or Kotlin source code, which is then compiled into JVM .class files. Note that at this stage, Java and Kotlin compilers can execute annotation processing tools (APT/KAPT) to generate source code (e.g., Dagger), and Kotlin compiler can run plugins to modify the internal code representation. Then, the D8 compiler takes these compiled classes, third-party libraries (JARs, AARs), and converts them into .dex files. However, if obfuscation and/or minification are enabled (which is almost always the case for release builds), R8 comes into play after D8. R8 obfuscates and optimises the bytecode, and additionally, R8 produces a source map file -- a special file listing all the changes and replacements. Obfuscation replaces human-readable names of various entities (classes, functions, fields, etc.) with very short, yet still unique names, for e

## Влияние Kotlin data-классов на вес приложения

DevFeed: [Влияние Kotlin data-классов на вес приложения](<https://devfeed.tech/articles/kotlin-data-23635.md>)

Original publisher: [Read original article](<https://habr.com/ru/companies/badoo/articles/545260/>)

Author: ChPr (Badoo)

Published: 2021-03-04T14:13:38Z

Content type: article

Language: ru

Sources: [Badoo EN](<https://devfeed.tech/sources/badoo-en.md>), [Badoo RU](<https://devfeed.tech/sources/badoo-ru.md>)

Topics: [data](<https://devfeed.tech/topics/data.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [R8](<https://devfeed.tech/topics/r8.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-development](<https://devfeed.tech/tags/android-development.md>), [data](<https://devfeed.tech/tags/data.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-compiler](<https://devfeed.tech/tags/kotlin-compiler.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

A Kotlin developer investigates the cost of using many data classes in an application. The article describes an experiment involving replacing data classes with ordinary classes and discusses how release optimizers such as R8 affect their generated methods.

### Source excerpt

Kotlin имеет много классных особенностей: null safety, smart casts, интерполяция строк и другие. Но одной из самых любимых разработчиками, по моим наблюдениям, являются data-классы. Настолько любимой, что их часто используют даже там, где никакой функциональности data-класса не требуется. В этой статье я с помощью эксперимента постараюсь понять, какова реальная цена использования большого количества data-классов в приложении. Я попробую удалить все data-классы, не сломав компиляцию, но сломав приложение, а потом расскажу о результатах и выводах этого эксперимента. Читать дальше ->

## Wildcard ProGuard/R8 Rule Can Remove Android Synchronization Calls

DevFeed: [Wildcard ProGuard/R8 Rule Can Remove Android Synchronization Calls](<https://devfeed.tech/articles/how-to-break-your-android-app-with-proguard-r8-24744.md>)

Original publisher: [Read original article](<https://medium.com/yazio-engineering/how-to-break-your-android-app-with-proguard-r8-6566bc387b63?source=rss----65bd178b00af---4>)

Author: Paul Woitaschek

Published: 2021-03-02T15:19:22Z

Content type: tutorial

Language: en

Sources: [YAZIO Engineering - Medium](<https://devfeed.tech/sources/yazio-engineering-medium.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Android Gradle Plugin](<https://devfeed.tech/topics/android-gradle-plugin.md>), [configuration](<https://devfeed.tech/topics/configuration.md>), [Testing](<https://devfeed.tech/topics/testing.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [android-gradle-plugin](<https://devfeed.tech/tags/android-gradle-plugin.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [configuration](<https://devfeed.tech/tags/configuration.md>), [instrumentation](<https://devfeed.tech/tags/instrumentation.md>), [proguard](<https://devfeed.tech/tags/proguard.md>), [r8](<https://devfeed.tech/tags/r8.md>), [testing](<https://devfeed.tech/tags/testing.md>)

### AI overview

An Android debugging article explains how instrumentation tests and a network call began hanging after an Android Gradle Plugin update. The cause was a ProGuard/R8 `-assumenosideeffects` rule using a wildcard for `android.util.Log`, which also matched superclass methods including synchronization methods on `Object`.

### Source excerpt

I recently updated the android gradle plugin to 4.0.0. While developing, everything went smoothly and at some point I was ready to cut a release. The very last manual testing of the release app bundle was also fine so no Proguard / R8 issues on the first sight either. Then I thought: Let me check the CI results again. Everything was fine, but: The instrumentation tests. Almost all of them were timing out. After inspecting the logs, they all hang at the end of the on-boarding. Strangely the loading spinner was loading for way longer than the timeout should be. So I tested it on my phone and faced the same results. At that time I had no idea it was caused by updating AGP, so I did a 2 hours long git bisect. Okay, now lets create a minimal self reproducible bug report because I found a huge bug in AGP, everyone should know about immediately. I created a Hello World project that was making a single network call and printed it results into a TextView. Strangely here it did not reproduce. After experimenting with the OkHttp configuration and testing if it was related to some gradle plugin, I finally had the idea that it might be related to R8. So I added my proguard configuration and now the network call hang! Let's locate the issue further. I was step by step removing lines from my proguard configuration until only a single line was left: -assumenosideeffects class android.util.Log { public * ; } Now what is this? How is that even slightly related to anything? It should remove the log spam of some third party libraries we're using. So I was asking Mads Ager. (he works on D8/R8) you have to be very careful with -assumenosideeffects The problem is that in order for -assumenosideeffects to have the effect of actually removing calls, it matches up the class hierarchy. Therefore, this rule says that anything public in android.util.Log and its superclasses has no side-effects. That include the synchronization methods defined on Object. So, please don't use * wildcards in conne

## How an R8 ProGuard rule can break Android application synchronization

DevFeed: [How an R8 ProGuard rule can break Android application synchronization](<https://devfeed.tech/articles/how-to-break-your-android-app-with-proguard-r8-26006.md>)

Original publisher: [Read original article](<https://medium.com/yazio-engineering/how-to-break-your-android-app-with-proguard-r8-6566bc387b63?source=rss-fbf9b6d94e65------2>)

Author: Paul Woitaschek

Published: 2020-06-08T05:52:07Z

Content type: tutorial

Language: en

Sources: [Stories by Paul Woitaschek on Medium](<https://devfeed.tech/sources/stories-by-paul-woitaschek-on-medium.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Android Gradle Plugin](<https://devfeed.tech/topics/android-gradle-plugin.md>), [Android](<https://devfeed.tech/topics/android.md>), [Testing](<https://devfeed.tech/topics/testing.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [android-gradle-plugin](<https://devfeed.tech/tags/android-gradle-plugin.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [bug](<https://devfeed.tech/tags/bug.md>), [ci](<https://devfeed.tech/tags/ci.md>), [configuration](<https://devfeed.tech/tags/configuration.md>), [proguard](<https://devfeed.tech/tags/proguard.md>), [r8](<https://devfeed.tech/tags/r8.md>), [synchronization](<https://devfeed.tech/tags/synchronization.md>), [testing](<https://devfeed.tech/tags/testing.md>)

### AI overview

The article investigates Android instrumentation tests and network calls hanging after an Android Gradle Plugin update. It traces the behavior to the R8 rule `-assumenosideeffects class android.util.Log { public * ; }`, which can treat synchronization methods inherited from `Object` as having no side effects. The author recommends avoiding wildcards with `-assumenosideeffects` and specifying exact signatures.

### Source excerpt

I recently updated the android gradle plugin to 4.0.0. While developing, everything went smoothly and at some point I was ready to cut a release. The very last manual testing of the release app bundle was also fine so no Proguard / R8 issues on the first sight either. Then I thought: Let me check the CI results again. Everything was fine, but: The instrumentation tests. Almost all of them were timing out. After inspecting the logs, they all hang at the end of the on-boarding. Strangely the loading spinner was loading for way longer than the timeout should be. So I tested it on my phone and faced the same results. At that time I had no idea it was caused by updating AGP, so I did a 2 hours long git bisect. Okay, now lets create a minimal self reproducible bug report because I found a huge bug in AGP, everyone should know about immediately. I created a Hello World project that was making a single network call and printed it results into a TextView. Strangely here it did not reproduce. After experimenting with the OkHttp configuration and testing if it was related to some gradle plugin, I finally had the idea that it might be related to R8. So I added my proguard configuration and now the network call hang! Let's locate the issue further. I was step by step removing lines from my proguard configuration until only a single line was left: -assumenosideeffects class android.util.Log { public * ; } Now what is this? How is that even slightly related to anything? It should remove the log spam of some third party libraries we're using. So I was asking Mads Ager. (he works on D8/R8) you have to be very careful with -assumenosideeffects The problem is that in order for -assumenosideeffects to have the effect of actually removing calls, it matches up the class hierarchy. Therefore, this rule says that anything public in android.util.Log and its superclasses has no side-effects. That include the synchronization methods defined on Object. So, please don't use * wildcards in conne

## R8 Optimization: Lambda Groups

DevFeed: [R8 Optimization: Lambda Groups](<https://devfeed.tech/articles/r8-optimization-lambda-groups-20959.md>)

Original publisher: [Read original article](<https://jakewharton.com/r8-optimization-lambda-groups/>)

Published: 2020-04-30T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [Android](<https://devfeed.tech/topics/android.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Java](<https://devfeed.tech/topics/java.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [apk](<https://devfeed.tech/tags/apk.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [lambda](<https://devfeed.tech/tags/lambda.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

An analysis of how R8 optimizes Kotlin lambda groups in Android applications, using compiled examples to compare the generated classes before and after optimization.

### Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". Lambda usage in Kotlin feels more pervasive than Java because of the functional nature of the Kotlin standard library. Some lambdas are merely syntactic constructs that are eliminated at compile-time through the use of inline functions. The rest materialize into whole classes for use at runtime. The mechanisms by which lambdas work was covered in the Android Java 8 support post, but here's a quick refresher: javac hoists lambda bodies to a package-private method and writes an invoke-dynamic bytecode for the target lambda type at the call-site. The JVM spins a class at runtime of the desired type and invokes the package-private method in the method body. Android does not ship this runtime support, so D8 performs a compile-time transformation to a class which implements the desired type and which invokes the package-private method. kotlinc skips the invoke-dynamic bytecode (even when targeting Java 8+) and generates full classes directly. Here's two Kotlin classes and some lambda usage that we can experiment with. class Employee( val id: String, val joined: LocalDate, val managerId: String? ) class EmployeeRepository(val allEmployees: () -> Sequence<Employee>) { fun joinedAfter(date: LocalDate) = allEmployees() .filter { it.joined >= date } .toList() fun reports(manager: Employee) = allEmployees() .filter { it.managerId == manager.id } .toList() } The EmployeeRepository class accepts a lambda which produces a sequence of employees and exposes two functions for listing the employees who joined after a particular date and those who report to a particular employee. Both functions use a lambda to filter the sequence to the desired items before converting to a list. Kotlin's approach to lambdas is immediately visible after compiling this class. $ kotlinc EmployeeRepos

## Which is better on Android: divide by 2 or shift by 1?

DevFeed: [Which is better on Android: divide by 2 or shift by 1?](<https://devfeed.tech/articles/which-is-better-on-android-divide-by-2-or-shift-by-1-20983.md>)

Original publisher: [Read original article](<https://jakewharton.com/which-is-better-on-android-divide-by-two-or-shift-by-one/>)

Published: 2020-04-23T00:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Kotlin Multiplatform](<https://devfeed.tech/topics/kotlin-multiplatform.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Java](<https://devfeed.tech/topics/java.md>), [R8](<https://devfeed.tech/topics/r8.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>), [writing](<https://devfeed.tech/tags/writing.md>)

### AI overview

This article investigates whether dividing by 2 or shifting by 1 is better on Android. It examines how Java and Kotlin source code is transformed by javac or kotlinc, D8/R8, and ART, using bytecode and Dalvik bytecode examples. The discussion is motivated by work porting the AndroidX collection library to Kotlin Multiplatform and by concerns about performance, readability, and compiler optimization.

### Source excerpt

I've been porting the AndroidX collection library to Kotlin multiplatform to experiment with binary compatibility, performance, tooling, and the different memory models. Some of the data structures in the library use array-based binary trees to store elements. The Java code has a lot of shifts to replace power-of-two multiplications and divides. When ported to Kotlin, these turn into the slightly-awkward infix operators which further obfuscate the intent of the code. I sampled a few people about bitwise shifts vs. multiplication/division and many had heard anecdotal claims of shifts having better performance, but everyone remained skeptical of whether it was true. Some assumed that one of the compilers seen before the code ran on a CPU would handle optimizing this case. In an effort to satisfy my curiosity (and partially to avoid Kotlin's infix bitwise operators) I set out to answer which is better and some other related questions. Let's go! Does anyone optimize this? There are three major compilers that code passes through before it hits the CPU: javac/kotlinc, D8/R8, and ART. Each of these has the opportunity to optimize. But do they? javac class Example { static int multiply(int value) { return value * 2; } static int divide(int value) { return value / 2; } static int shiftLeft(int value) { return value << 1; } static int shiftRight(int value) { return value >> 1; } } This Java can be compiled with javac from JDK 14 and the resulting bytecode can be displayed with javap. $ javac Example.java $ javap -c Example Compiled from "Example.java" class Example { static int multiply(int); Code: 0: iload_0 1: iconst_2 2: imul 3: ireturn static int divide(int); Code: 0: iload_0 1: iconst_2 2: idiv 3: ireturn static int shiftLeft(int); Code: 0: iload_0 1: iconst_1 2: ishl 3: ireturn static int shiftRight(int); Code: 0: iload_0 1: iconst_1 2: ishr 3: ireturn } Every method starts with iload_0 which loads the first argument value. The multiply and divide methods both then have

## D8 Optimization: Assertions

DevFeed: [D8 Optimization: Assertions](<https://devfeed.tech/articles/d8-optimization-assertions-20929.md>)

Original publisher: [Read original article](<https://jakewharton.com/d8-optimization-assertions/>)

Published: 2020-03-25T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Java](<https://devfeed.tech/topics/java.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [java](<https://devfeed.tech/tags/java.md>), [jvm](<https://devfeed.tech/tags/jvm.md>), [main-thread](<https://devfeed.tech/tags/main-thread.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>), [thread](<https://devfeed.tech/tags/thread.md>)

### AI overview

This article explains how D8 and R8 optimize Java assert statements in Android applications. Because Android does not support enabling Java assertions, D8 can remove the assertion check and its dependent expressions, allowing dead-code elimination. The example uses an assertion to enforce main-thread access when generating unique IDs, and the article connects this optimization to R8's SSA-based analysis.

### Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". The assert keyword is quirky Java language syntax used for testing invariants. That is: things you expect to always be true. Its syntax has two forms: assert <bool-expression>; assert <bool-expression> : <expression>; The first expression will only be evaluated at runtime if the -ea (enable assertions) flag is set on the JVM. The second expression, if present, is used as the argument to the AssertionError constructor that's thrown if the first expression returns false. As an Android developer you might not be too familiar with assert. This is because every Android app runs on a VM which is forked from a shared "zygote" process which has assertions disabled. Thus, even if you put an assert in your code, there is no way to actually enable it. So why bother talking about it? Well it turns out they're about to become useful on Android for the first time! Today's behavior assert statements guard things which must always be true in order for your program to execute correctly. Let's write one. class IdGenerator { private int id = 0; int next() { assert Thread.currentThread() == Looper.getMainLooper().getThread(); return id++; } } This class creates unique IDs and guarantees they're unique by only allowing calls from the main thread. If this class was called concurrently from multiple threads you might see duplicate values. Sure it's a little contrived and there's things like @MainThread which is checked by Lint but we're focusing on assert so roll with it. The Null Data Flow Analysis post introduced the SSA form that R8 uses to eliminate branches of code which it can prove will never be executed. The SSA for the next() method when parsed from Java bytecode looks very roughly like this: D8 knows that Android does not support Java assertions. It will remove the check an

## Diving deep into Android Dex bytecode

DevFeed: [Diving deep into Android Dex bytecode](<https://devfeed.tech/articles/diving-deep-into-android-dex-bytecode-38625.md>)

Original publisher: [Read original article](<https://krossovochkin.com/posts/2020_02_02_diving_deep_into_android_dex_bytecode/>)

Published: 2020-02-02T00:00:00Z

Content type: tutorial

Language: en

Sources: [Vasya Drobushkov](<https://devfeed.tech/sources/vasya-drobushkov.md>)

Topics: [Android](<https://devfeed.tech/topics/android.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Java](<https://devfeed.tech/topics/java.md>), [Mobile](<https://devfeed.tech/topics/mobile.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [bytecode](<https://devfeed.tech/tags/bytecode.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [inlining](<https://devfeed.tech/tags/inlining.md>), [java](<https://devfeed.tech/tags/java.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [memory](<https://devfeed.tech/tags/memory.md>), [performance](<https://devfeed.tech/tags/performance.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This practical guide explains how Kotlin and Java code is transformed into Android DEX bytecode. It describes examining Java bytecode, the role of the Dalvik bytecode format and Android Runtime, and the compilation tools kotlinc, javac, d8, and R8, with attention to possible memory and performance effects.

### Source excerpt

Source Introduction Modern Android development is based on Kotlin, which is interoperable with Java. Whenever we use some cool feature from Kotlin (say High-order functions) under the hood (when running on JVM) the feature is implemented in terms of Java bytecode. This might lead to some overheads in memory and performance if used without caution (for example excessive usage of lambdas with parameters without inlining might produce a lot of anonymous classes and put additional pressure on GC).

## Fixing the Initial Dispatchers.Main Delay in Kotlin Coroutines

DevFeed: [Fixing the Initial Dispatchers.Main Delay in Kotlin Coroutines](<https://devfeed.tech/articles/a-dispatcher-of-many-threads-37550.md>)

Original publisher: [Read original article](<https://colintheshots.com/writing/a-dispatcher-of-many-threads-part-1-2/>)

Published: 2019-12-19T03:02:18Z

Content type: tutorial

Language: en

Sources: [Colin The Shots](<https://devfeed.tech/sources/colin-the-shots.md>)

Topics: [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [kotlin-coroutines](<https://devfeed.tech/topics/kotlin-coroutines.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Android](<https://devfeed.tech/topics/android.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [Android Studio](<https://devfeed.tech/topics/android-studio.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-studio](<https://devfeed.tech/tags/android-studio.md>), [builds](<https://devfeed.tech/tags/builds.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-coroutines](<https://devfeed.tech/tags/kotlin-coroutines.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This article explains an initial delay of up to a quarter second when Android apps first use Kotlin Coroutines' Dispatchers.Main. It attributes the delay to ServiceLoader triggering a checksum of the entire JAR inside the APK and describes a stable fix using Kotlin coroutines 1.3.3 or higher, required Proguard rules, and R8 optimization.

### Source excerpt

Kotlin Coroutines have been almost unanimously received with applause by the Android software development community. However, there are some significant issues I have noticed in practice that are

## ProGuard & R8: Part 2

DevFeed: [ProGuard & R8: Part 2](<https://devfeed.tech/articles/proguard-r8-part-2-32346.md>)

Original publisher: [Read original article](<https://dustn.dev/post/2019-11-20-android-build-pipeline-hands-on/>)

Author: dustin@dustn.dev (Dustin Summers)

Published: 2019-11-20T09:00:00Z

Content type: tutorial

Language: en

Sources: [Dustin Summers](<https://devfeed.tech/sources/dustin-summers.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Android](<https://devfeed.tech/topics/android.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Android Studio](<https://devfeed.tech/topics/android-studio.md>), [Java](<https://devfeed.tech/topics/java.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-studio](<https://devfeed.tech/tags/android-studio.md>), [code](<https://devfeed.tech/tags/code.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [java](<https://devfeed.tech/tags/java.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [proguard](<https://devfeed.tech/tags/proguard.md>), [proguard-android-r8-smali-dalvik-jvm-kotlin-art-gradle-java](<https://devfeed.tech/tags/proguard-android-r8-smali-dalvik-jvm-kotlin-art-gradle-java.md>), [r8](<https://devfeed.tech/tags/r8.md>), [sdk](<https://devfeed.tech/tags/sdk.md>), [terminal](<https://devfeed.tech/tags/terminal.md>)

### AI overview

A hands-on tutorial covering the Android build pipeline with ProGuard and R8. It walks through compiling Java or Kotlin source code, using Android Build Tools, and examining generated bytecode.

### Source excerpt

This blog post is the second in a series to teach about the build tools ProGuard and R8, and the first in the hands-on portion of the series. In the first post I talked about the Android Build Pipeline. In this blog, I would like to actually reinforce those concepts with hands on exercises. If you haven't read the first blog on this topic, this is part two in that series, so I highly suggest going back and understanding that material first.

## Understanding the Android Build Pipeline with ProGuard and R8

DevFeed: [Understanding the Android Build Pipeline with ProGuard and R8](<https://devfeed.tech/articles/proguard-r8-part-1-32347.md>)

Original publisher: [Read original article](<https://dustn.dev/post/2019-11-6-understanding-the-android-build-pipeline/>)

Author: dustin@dustn.dev (Dustin Summers)

Published: 2019-11-06T12:08:40Z

Content type: tutorial

Language: en

Sources: [Dustin Summers](<https://devfeed.tech/sources/dustin-summers.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Code](<https://devfeed.tech/topics/code.md>), [obfuscation](<https://devfeed.tech/topics/obfuscation.md>), [software-development](<https://devfeed.tech/topics/software-development.md>), [Software](<https://devfeed.tech/topics/software.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [compilation](<https://devfeed.tech/tags/compilation.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [proguard](<https://devfeed.tech/tags/proguard.md>), [proguard-android-r8-smali-dalvik-jvm-kotlin-art-gradle-java](<https://devfeed.tech/tags/proguard-android-r8-smali-dalvik-jvm-kotlin-art-gradle-java.md>), [r8](<https://devfeed.tech/tags/r8.md>), [software-development](<https://devfeed.tech/tags/software-development.md>), [tutorials](<https://devfeed.tech/tags/tutorials.md>)

### AI overview

A tutorial explaining the Android build pipeline and where ProGuard and R8 fit into it. It introduces compilation stages, optimization, shrinking, and code obfuscation, with an emphasis on understanding and diagnosing how these tools transform source code into bytecode.

### Source excerpt

Tools such as R8 and ProGuard are available for free, but to many they are a black box that code goes into and stuff comes out. My goal is to demystify the black box and teach developers how to properly diagnose the code going into and coming out of these build tools. It will also explain why you should care and why applying these tools should be a priority before shipping any code into the wild.

## R8 Optimization: Enum Switch Maps

DevFeed: [R8 Optimization: Enum Switch Maps](<https://devfeed.tech/articles/r8-optimization-enum-switch-maps-20958.md>)

Original publisher: [Read original article](<https://jakewharton.com/r8-optimization-enum-switch-maps/>)

Published: 2019-10-16T00:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [Android](<https://devfeed.tech/topics/android.md>), [Java](<https://devfeed.tech/topics/java.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [java](<https://devfeed.tech/tags/java.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This article explains how Java enum switch statements are compiled and how R8 optimizes them. It describes the generated switch-map array that translates enum ordinals into stable branch values, allowing the application to continue working when enum constants are reordered and only part of the code is recompiled.

### Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". The previous post on R8 covered enum ordinals which then allowed branch elimination to apply to a switch statement. In that post, the full bytecode for switch on an enum was omitted because there's actually more to the optimization. Let's start with a simple enum and a switch over its contents in two separate source files (this will be important later). enum Greeting { FORMAL, INFORMAL } class Main { static String greetingType(Greeting greeting) { switch (greeting) { case FORMAL: return "formal"; case INFORMAL: return "informal"; default: throw new AssertionError(); } } public static void main(String... args) { System.out.println(greetingType(Greeting.INFORMAL)); } } If we compile and run these files the output is as expected. $ javac Greeting.java Main.java $ java -cp . Main informal The bytecode in the previous post showed that the compiler produces a call to ordinal() which is then used in the switch. But if that was all that the compiler did, re-ordering the constants of Greeting would break the output of Main. enum Greeting { - FORMAL, INFORMAL + INFORMAL, FORMAL } After changing the constant order, we can recompile only Greeting.java and yet the application still produces the correct output. $ javac Greeting.java $ java -cp . Main informal If the bytecode was only relying on the value of ordinal(), this code would have produced "formal". Into The Bytecode To understand how this works we can look at the Java bytecode of greetingType. $ javap -c Main.class class Main { static java.lang.String greetingType(Greeting); Code: 0: getstatic #2 // Field Main$1.$SwitchMap$Greeting:[I 3: aload_0 4: invokevirtual #3 // Method Greeting.ordinal:()I 7: iaload 8: lookupswitch { 1: 36 2: 39 default: 42 } 36: ldc #4 // String formal 38: areturn 39: ldc #5 // String informa

## R8 Optimization: Enum Ordinals and Names

DevFeed: [R8 Optimization: Enum Ordinals and Names](<https://devfeed.tech/articles/r8-optimization-enum-ordinals-and-names-20957.md>)

Original publisher: [Read original article](<https://jakewharton.com/r8-optimization-enum-ordinals-and-names/>)

Published: 2019-10-09T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Optimization](<https://devfeed.tech/topics/optimization.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Java](<https://devfeed.tech/topics/java.md>), [Android](<https://devfeed.tech/topics/android.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [display](<https://devfeed.tech/tags/display.md>), [enum](<https://devfeed.tech/tags/enum.md>), [java](<https://devfeed.tech/tags/java.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>), [serialization](<https://devfeed.tech/tags/serialization.md>)

### AI overview

This article explains how R8 optimizes Java enums in Android applications. It focuses on replacing compile-time-known enum ordinal lookups with integer values, enabling switch-branch elimination, and inlining enum name access when appropriate.

### Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". Enums are (and have always been!) a recommended way to model a fixed set of constants. Most commonly an enum only provides a set of possible constants and nothing more. But being full classes, enums can also carry helper methods and fields (both instance and static) or even implement interfaces. A common optimization for enums in tools that perform whole-program optimization is to replace simple occurrences (i.e., those which don't have fields, methods, or interfaces) with integer values. However, there are other optimizations which are applicable to all enums that are still available. Ordinal Each enum constant has an ordinal() which returns its position in the list of all constants. Since the ordinal range is always [0, N), it can be used for indexing into other zero-based data structures such as arrays or even bits. The most common usage is actually by the Java compiler itself for switch statements over enums. enum Greeting { FORMAL { @Override String greet(String name) { return "Hello, " + name; } }, INFORMAL { @Override String greet(String name) { return "Hey " + name + '!'; } }; abstract String greet(String name); static String type(Greeting greeting) { switch (greeting) { case FORMAL: return "formal"; case INFORMAL: return "informal"; default: throw new AssertionError(); } } } The compiled bytecode reveals the hidden call to ordinal(). [000a34] Greeting.type:(LGreeting;)Ljava/lang/String; 0000: invoke-virtual {v1}, LGreeting;.ordinal:()I 0003: move-result v1 ⋮ If we call this method with one of the constants, an opportunity for optimization presents itself. public static void main(String... args) { System.out.println(Greeting.type(Greeting.INFORMAL)); } As this is the only usage of type in our whole application, R8 inlines the method. [000b60] Greeter.ma

## R8 Optimization: Class Reflection and Forced Inlining

DevFeed: [R8 Optimization: Class Reflection and Forced Inlining](<https://devfeed.tech/articles/r8-optimization-class-reflection-and-forced-inlining-20956.md>)

Original publisher: [Read original article](<https://jakewharton.com/r8-optimization-class-reflection-and-forced-inlining/>)

Published: 2019-09-25T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [Android](<https://devfeed.tech/topics/android.md>), [obfuscation](<https://devfeed.tech/topics/obfuscation.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.md>), [inlining](<https://devfeed.tech/tags/inlining.md>), [obfuscation](<https://devfeed.tech/tags/obfuscation.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>)

### AI overview

This article explains how R8 optimizes Java class reflection in Android applications. It contrasts static class literals with instance getClass() calls, then describes how whole-program analysis can replace reflective calls with known class references and string constants. It also examines a case where method inlining is blocked by method-size limits and introduces forced inlining through R8 configuration rules compatible with ProGuard.

### Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". The previous post on R8 covered method outlining which automatically de-duplicated code. This was actually a detour from what I had promised was next at the end of the class constant operations post which preceded it. So let's get back on track. Class constant operations allow R8 to take calls such as MyActivity.class.getSimpleName() and replace it with the string literal "MyActivity". This was presented in the context of log tags, where you might write that expression instead of the string literal so that the tag always reflects the actual class name, even after obfuscation. This works great in a static context where the MyActivity.class literal is fixed, but it does not work when used on an instance. Instance reflection When dealing with an instance, the Class reference is obtained by calling getClass() instead of a MyActivity.class literal. This operation is not terribly expensive, but it is still a form of reflection. class MyActivity extends Activity { @Override void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String name = this.getClass().getSimpleName(); Log.e(name, "Hello!"); } } The getClass() API is just a normal method on every Object and appears as a normal invoke-virtual in bytecode. [0003d0] MyActivity.onCreate:(Landroid/os/Bundle;)V 0000: invoke-super {v1, v2}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V 0003: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; 0006: move-result-object v2 0007: invoke-virtual {v2}, Ljava/lang/Class;.getSimpleName:()Ljava/lang/String; 000a: move-result-object v2 Since R8 is performing whole-program analysis, it knows that there are no subtypes of MyActivity even though it's not marked as final. As a result, it can replace calls to this.getClass() with MyAct

## R8 Optimization: Method Outlining

DevFeed: [R8 Optimization: Method Outlining](<https://devfeed.tech/articles/r8-optimization-method-outlining-20960.md>)

Original publisher: [Read original article](<https://jakewharton.com/r8-optimization-method-outlining/>)

Published: 2019-04-11T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [R8](<https://devfeed.tech/topics/r8.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [Android](<https://devfeed.tech/topics/android.md>), [Code](<https://devfeed.tech/topics/code.md>), [JSON](<https://devfeed.tech/topics/json.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.md>), [examples](<https://devfeed.tech/tags/examples.md>), [exception](<https://devfeed.tech/tags/exception.md>), [java](<https://devfeed.tech/tags/java.md>), [json](<https://devfeed.tech/tags/json.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>), [reduce](<https://devfeed.tech/tags/reduce.md>)

### AI overview

This article explains how R8 optimization can make duplicated generated code smaller than a generated helper method in an Android APK. Using Moshi-style JSON parsing as the example, it discusses repeated exceptions and string-building logic generated for non-null properties, and why R8 method outlining and related optimizations affect the final bytecode size.

### Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". I recently wrote about the economics of generated code which talked about performing optimizations to generated code that aren't worthwhile in manually-written code. While the examples in that post were motivated by changes to code generators that I had worked on in the past, it also resulted in some new changes being made. One change proposed to Moshi, a JSON serializer, replaced its generated strings with StringBuilder to de-duplicate the constant parts. Each non-null property in your JSON model generates an exception to ensure non-null values are read from the JSON. name = stringAdapter.fromJson(reader) ?: throw JsonDataException( - "Non-null value 'name' was null at ${reader.path}") + StringBuilder("Non-null value '").append("name") + .append("' was null at ").append(reader.path).toString()) A second exception is generated when that non-null property lacks a default value and no value was present in the JSON. return Person( name = name ?: throw JsonDataException( - "Required property 'name' missing at ${reader.path}"), + StringBuilder("Required property '").append("name") + .append("' missing at ").append(reader.path).toString()), These two diffs are the result of applying the advice from that post. Each of these exceptions are generated for every property in the type. This means if you have a type with 10 properties you get 20 exceptions generated (assuming they're non-null and don't have default values). This winds up creating a lot of StringBuilder bytecode! One way to reduce this bytecode bloat is to generate a private method which takes four arguments (prefix, name, suffix, path) and returns the final string. This was proposed as part of the change to Moshi. We ultimately duplicated the code instead of generating a method because it ends up optimizing

[Next page](<https://devfeed.tech/topics/r8.md?cursor=WyIyMDE5LTA0LTExVDAwOjAwOjAwKzAwOjAwIiwgIjYwZDViZDMwLTkzZDktNGJkYy04OTM0LWJkNGYxNDQyNGNlZSJd>)