Non-Transitive R Classes
Tags: android, build, gradle, performance
Published: 2023-07-17 06:47:26

---
title: Non-Transitive R Classes
published: true
cover_image: https://s3-us-west-2.amazonaws.com/my-blogresources/IMAG1121.jpg
description: Improving Build Speed by using non-transitive R classes
tags: android, build, gradle, performance
series: Quality Quest
---

While upgrading my android project to use AGP 8.0.0, I noticed that android build analyzer had a recommendation to use non-transitive R classes to improve build speed. 

![Build Analyzer Recommendation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ubmtjopkch8mno0wlzd.png)

I was curious to know what it is and how it works. So, I did some research and here's what I found.

## Why

Non-transitive R classes have been around for a while, but it was not enabled by default. With AGP 8.0.0, it is enabled by default. For the curious minds, I have included a blog that talks about the history of R classes and non-transitive R classes at the end of this article.

Non-transitive R classes enable namespacing of each library’s R class so that its R class includes only the resources declared in the library itself and none from the library’s dependencies, thereby reducing the size of the R class for that library.

For example, if the code uses a default animation `R.anim.nav_default_enter_anim` which comes from the `androidx.navigation:navigation-ui-ktx` dependency. Without using non-transitive R classes, The 'R' class of module has references to its own resources and transitive references to resources of navigation UI library.

  ```kotlin
  import com.learning.compose.R
  ...

    .setStartAnimations(activity, R.anim.nav_default_enter_anim, R.anim.nav_default_exit_anim)

  ```

With non-transitive R classes enabled, this will force us to use the fully qualified R class name to access the resources in the dependency module, thus reducing the references in the 'R' class of 'compose' module. And also by referencing using fully qualified R class name, the Compose module doesn't have to be recompiled and the build speed is improved.


  ```kotlin
  .setStartAnimations(activity, androidx.navigation.ui.R.anim.nav_default_enter_anim, androidx.navigation.ui.R.anim.nav_default_exit_anim)
  ```

Since the dependencies become more explicit with non-transitive R classes, the modularity of the code increases. It also decreases  complexity, since resources cannot come from transitive dependencies. It also increases the build speed(both *clean* and *incremental*) as promised by [Android Developers from Android Dev Summit '21](https://youtu.be/S_zZRBJxTQ0?t=69).

## What to do

If you use a resource from another dependency/module,
- If your android project is 100% Kotlin Only, You are in luck. You can `alias` imports of R classes of dependency modules to access resources in that module.
- If your project has some Java code references, You have to use fully qualified R class name to access resources in the dependency module

Also, If you use a resource from another module, but you do not declare a dependency on that module, and you do not want to declare a dependency, you could simply duplicate resources in the app module

## How to do

Use Android Studio's `Refactor -> Migrate to non-transitive R classes` to migrate the project to use non-transitive R classes
  - This will, 
    - Adds the below in gradle.properties

    ```properties
    android.nonTransitiveRClass=true
    ```
  
    - Updates fully qualified R class name wherever it finds the non-transitive R class usage

      ```kotlin
      .setStartAnimations(activity, androidx.navigation.ui.R.anim.nav_default_enter_anim, androidx.navigation.ui.R.anim.nav_default_exit_anim)
      ```

Additionally, If the code base is in Kotlin, You could `alias` the fully qualified package name of the R class to access the resources

  ```kotlin
  import androidx.navigation.ui.R as NavUiR

  ...
    .setStartAnimations(activity, NavUiR.anim.nav_default_enter_anim, NavUiR.anim.nav_default_exit_anim)
    .setExitAnimations(activity, NavUiR.anim.nav_default_pop_enter_anim, NavUiR.anim.nav_default_pop_exit_anim)
  ```

Here are some references to the articles that I found useful

- [Improve Build speed Recommendation](https://developer.android.com/build/optimize-your-build#use-non-transitive-r-classes)
- [History of R classes & non-transitive R classes](https://www.mobileit.cz/Blog/Pages/r-class.aspx)