17

My application uses old architecture components. I want to move to new android architecture components.

For this purpose I added room related dependencies in the beginning, after that build was normal.

But when I tried adding dependencies for Lyfecycles, LiveData and ViewModel, as mentioned here.

Application build process slowed down considerably, 5 mins and more time is required to build apk.

Following dependecies added in app's build.gradle :

    compile "android.arch.lifecycle:runtime:1.0.0-alpha5"
    compile "android.arch.lifecycle:extensions:1.0.0-alpha5"
    annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha5"

Also I have to enable jack for Java 8 compatibility, as follows :

defaultConfig {
........
        jackOptions {
            enabled true
        }
    }

After adding all these componets build process has slowed down considerably. I tried making some custom VM option changes for some parameters by going to Help -> Edit custom VM options

-Xmx5120m

I set it to almost 5 GBs but nothing worked for me. My machine has enough hardware I believe. ( 8 GB RAM, Windows 10, 1TB HDD, AMD A8)

My application makes use of many google services, like Gmail API, Firebase APIs, some other libraries did I exhausted 64K reference limit ? But I have already enabled the multidexing as mentioned here.

Did this happened because of new architecture components or something else ? How do I make build process faster ?

Update :

One of the answer below by Budius suggested a script which will show timings taken by each build process, I executed it in my application here are the findings :

BUILD SUCCESSFUL

Total time: 18 mins 28.44 secs
Task timings:
    480ms  :app:mergeDebugResources
   2516ms  :app:processDebugResources
 487725ms  :app:transformClassesWithPreJackPackagedLibrariesForDebug
  29213ms  :app:transformClassesWithPreJackRuntimeLibrariesForDebug
    752ms  :app:transformResourcesWithMergeJavaResForDebug
 556894ms  :app:transformJackWithJackForDebug
   5184ms  :app:transformNativeLibsWithMergeJniLibsForDebug
  17524ms  :app:packageDebug

Most of the timings are taken by Jack.

I tried the canary version suggested in below answer by Bryan following is output of the timing taken for build process :

BUILD SUCCESSFUL in 6m 11s
42 actionable tasks: 33 executed, 9 up-to-date
Task timings:
    608ms  :app:preDebugBuild
    350ms  :app:mergeDebugResources
    394ms  :app:processDebugManifest
   2543ms  :app:processDebugResources
   9410ms  :app:javaPreCompileDebug
  46585ms  :app:compileDebugJavaWithJavac
    262ms  :app:compileDebugShaders
    395ms  :app:mergeDebugAssets
   5835ms  :app:packageInstantRunResourcesDebug
  98922ms  :app:transformClassesWithDesugarForDebug
    334ms  :app:transformClassesWithExtractJarsForDebug
   7765ms  :app:transformClassesWithInstantRunVerifierForDebug
  23117ms  :app:transformNativeLibsWithMergeJniLibsForDebug
  10128ms  :app:transformResourcesWithMergeJavaResForDebug
  16565ms  :app:transformClassesWithInstantRunForDebug
  11825ms  :app:transformClassesWithInstantRunSlicerForDebug
  84703ms  :app:transformClassesWithDexBuilderForDebug
  17061ms  :app:transformDexArchiveWithDexMergerForDebug
   1706ms  :app:transformDexWithInstantRunDependenciesApkForDebug
   9770ms  :app:transformDexWithInstantRunSlicesApkForDebug
  10571ms  :app:packageDebug
   1387ms  :app:buildInfoGeneratorDebug

So I removed jack & switched to this canary version, build is faster than previous for sure but still slow for use.

Prashant
  • 4,474
  • 8
  • 34
  • 82
  • 1
    It will obviously slow down process, but 5 mins is too much, because it does compile time annotation processing and it will create new class files during compilation phase and adding support for 2 way data binding .. could you share gradle logs using command ... gradlew build > myLogs.txt .. I just want to see how much 2 way binding stuff have you implemented or is it because of something else .. if possible share your app level gradle but post hiding signingConfigs keyAlias and passwords :) – Anukalp Katyal Aug 08 '17 at 09:20
  • To measure build time you can run `./gradlew assembleDebug --scan` and go to https://scans.gradle.com – Evgenii Vorobei Feb 19 '19 at 11:26

7 Answers7

8

A lot on your question is based of assumptions that this or that might be, that there are "lots". But time is something very easy to measure, and gradle divides the build process into several smaller tasks. So I guess your best action is to measure each task and than you can compare what's taking so long.

Here is a script I made to measure build times, just add it do the root folder of your project and on your top-level gradle file add apply from: 'time.gradle'

timer.gradle

import java.util.concurrent.TimeUnit

class TimingsListener implements TaskExecutionListener, BuildListener {
    private long startTime
    private timings = []

    @Override
    void beforeExecute(Task task) {
        startTime = System.nanoTime()
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        def ms = TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
        timings.add([ms, task.path])
    }

    @Override
    void buildFinished(BuildResult result) {
        println "Task timings:"
        for (timing in timings) {
            if (timing[0] >= 250) {
                printf "%7sms  %s\n", timing
            }
        }
    }

    @Override
    void buildStarted(Gradle gradle) {}

    @Override
    void projectsEvaluated(Gradle gradle) {}

    @Override
    void projectsLoaded(Gradle gradle) {}

    @Override
    void settingsEvaluated(Settings settings) {}
}

gradle.addListener new TimingsListener()
Budius
  • 39,391
  • 16
  • 102
  • 144
  • Thats good suggestion, I will see the timings taken by each sub tasks during build process, then may be update my question, thanks – Prashant Aug 04 '17 at 04:57
  • I'd advise using ./gradlew --profile which will output an html with breakdown times. Usually they will be on ./build/reports/profile – Fabio Aug 09 '17 at 01:08
  • I copied file timer.gradle to root of my project and then in top level build.gradle I added the line 'apply from time.gradle' I got this error Error:(26, 0) Could not get unknown property 'from' for root project 'MyApp' of type org.gradle.api.Project. – Prashant Aug 09 '17 at 05:57
  • @pcj edited my answer, it missed this symbol `:`. It has to be `apply from: 'timer.gradle'` – Budius Aug 09 '17 at 06:34
  • @pcj I've checked your results, it seems most of the time is and Jack related operations so my suggestion is to disable/remove Jack compiler. As mentioned in Bryan answer, it's deprecated and should not be used. So: remove Jack and make sure that you're running latest version of Gradle and Gradle Android plugin. Than check again the timers – Budius Aug 09 '17 at 10:25
6

The Jack Toolchain is deprecated, and was still in an experimental phase before its deprecation. Although the process of generating code can be slow (as @FlorescuGeorgeCătălin mentioned) it doesn't usually cause such excessively slow build times. I suspect the cause of your slow build times is the Jack Toolchain; as it is notoriously slow.

If you want Java 8 language features I suggest you move to the canary version of Android Studio 3.0 which has them built-in.

If that isn't an option you could use Retrolambda instead, which includes most of the same Java 8 language features.

Bryan
  • 14,756
  • 10
  • 70
  • 125
2

Since the library has an annotation processor, he must generate new code into generated classes. Dagger is also a library that generate code. Butterknife the same.

You can found them into app/build/generated project folder.

You can check more about annotation processor here.

Also can be from your HDD. An SSD could give you much more processing power.

Cătălin Florescu
  • 5,012
  • 1
  • 25
  • 36
1

Did you set Gradle to Offline Work and try to Edit custom VM options to bigger heap size?

Another solution is upgrade Android Studio to Android Studio 3.0 which also increase the build speed

nhoxbypass
  • 9,695
  • 11
  • 48
  • 71
1

File -> Settings -> (Left Side) Build, Execution, Development -> Build Tools -> Gradle

Under the "Global Gradle Settings" there will be a check box named "Offline Work". Check it.

Did you do it?

Efe AYDIN
  • 193
  • 12
1

Add the following in the build.gradle inside android {}

dexOptions {
    incremental true
    javaMaxHeapSize "4g"
}

Set the following in the gradle.properties file:

org.gradle.parallel=true
org.gradle.daemon=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
android.enableBuildCache=true
org.gradle.caching=true
AnupamChugh
  • 1,779
  • 1
  • 25
  • 36
0

This is a long shot, but is there a real android device connected to your testing machine? I actually notice that my AS runs really slowly if I have my test devices connected, maybe the adb is having trouble and that slows down the system.

Alternatively, I did upgrade to a 16gb ram i7 processor from my old machine and things started running much faster.

Bqin1
  • 467
  • 1
  • 9
  • 19