<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Nelson Osacky on Medium]]></title>
        <description><![CDATA[Stories by Nelson Osacky on Medium]]></description>
        <link>https://medium.com/@runningcode?source=rss-85419ad6ecd1------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*8ckYQIt_1jfIj58Chv_zJw.jpeg</url>
            <title>Stories by Nelson Osacky on Medium</title>
            <link>https://medium.com/@runningcode?source=rss-85419ad6ecd1------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 13 Apr 2026 08:14:15 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@runningcode/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Estimating if the remote build cache is worth it using the internals of Gradle. (Part 2)]]></title>
            <link>https://medium.com/@runningcode/how-fast-does-my-internet-need-to-be-to-use-the-gradle-remote-build-cache-part-2-1bc2b171f19?source=rss-85419ad6ecd1------2</link>
            <guid isPermaLink="false">https://medium.com/p/1bc2b171f19</guid>
            <category><![CDATA[gradle]]></category>
            <category><![CDATA[developer-productivity]]></category>
            <category><![CDATA[caching]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Nelson Osacky]]></dc:creator>
            <pubDate>Mon, 13 Apr 2020 13:22:45 GMT</pubDate>
            <atom:updated>2020-04-13T18:38:26.613Z</atom:updated>
            <content:encoded><![CDATA[<h3>How fast does my internet need to be to use the Gradle Remote Build Cache? (Part 2)</h3><p>In this post well estimating if the remote build cache is worth it using the internals of Gradle. This post is part of a series that dives in the details of whether it is better to rerun tasks locally or download them from the remote build cache on a slow internet connection. <a href="https://medium.com/@runningcode/how-fast-does-my-internet-need-to-be-to-use-the-gradle-remote-build-cache-part-1-4acaa6f9a2fa">Read Part 1</a> first for the basics of estimating build cache performance.</p><h3>Diving into Gradle</h3><p>This post involves a bit of Gradle hackery using internal APIs. If you want to skip straight to the code, <a href="https://github.com/runningcode/gradle-doctor/pull/52">here it is.</a> To perform an estimation on your project, scroll to the bottom of this post.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/589/1*2--z_6rLPnCie1pndjJsLA.png" /></figure><h3>Estimating benefits of the remote build cache</h3><p>To create a real world estimate for a build we will:</p><ol><li>Run a typical build for a project and measure the <strong>build duration</strong></li><li>Create a map of build cache keys for all the tasks in the project</li><li>Map the build cache keys to tasks which ran</li><li>Find all recently-added artifacts in the build cache</li><li>Sum their size</li><li><strong>Sum of build cache artifacts </strong>/<strong> build duration </strong>= <strong>minimum remote cache connection speed</strong></li></ol><p>Sounds simple enough? Let’s get to it.</p><h3>Automating the estimation</h3><h4>Run a typical build for a project</h4><p>Let’s estimate how long ./gradlew :application:assembleDebug takes.</p><p>The first time we run it, it takes 60 seconds. But if we run it again, it only takes 3 seconds because all the tasks are up to date or cached. We need to temporarily disable task caching by forcing a series of Gradle tasks to re-run.</p><p>The following code snippet will re-run all SourceTasks in the module:</p><pre>tasks.withType(SourceTask).configureEach {<br>  outputs.upToDateWhen { false }<br>}</pre><p>With this in our buildscript, we can re-run ./gradlew :application:assembleDebug and get a consistent 55 second <strong>build duration </strong>excluding configuration time<strong>.</strong></p><h4>Create map of build cache keys for all tasks in the project</h4><p>It sounds straightforward, but unfortunately, there is no public API to get a build cache key for a task.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Bt474z9fjFJGTe1V9XNFtQ.png" /><figcaption>The build cache key doesn’t have a public api, but is included in build scans.</figcaption></figure><p>We can see the build cache key easily in the build scans, so Gradle must be producing it somehow. I did some poking around in the Gradle open source project to find <a href="https://github.com/gradle/gradle/blob/master/subprojects/base-services/src/main/java/org/gradle/internal/operations/BuildOperationListener.java">BuildOperationListener</a> . This is a powerful internal API, but also quite dangerous if misused.</p><p>The API gives us all sorts of build events. We are going to listen for <a href="https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/java/org/gradle/api/internal/tasks/SnapshotTaskInputsBuildOperationType.java">SnapshotTaskInputsBuildOperationType</a> since it contains two pieces of information that we need:</p><ol><li>hashBytes — the build cache key</li><li>the parent task id — needed to determine if the task was executed</li></ol><p><a href="https://github.com/runningcode/gradle-doctor/blob/master/doctor-plugin/src/main/java/com/osacky/doctor/BuildOperations.kt#L44">We put all these events in a map.</a></p><h4>Map the build cache keys to tasks which ran</h4><p>To find whether or not a task ran, we need to listen for another type of event using the same <a href="https://github.com/gradle/gradle/blob/master/subprojects/base-services/src/main/java/org/gradle/internal/operations/BuildOperationListener.java">BuildOperationListener</a> : the ExecuteTaskBuildOperationType event. It has the two other pieces we need:</p><ol><li>the parent task id to connect to the build cache key</li><li>skipMessage — null if the task was executed</li></ol><p>With both ExecuteTaskBuildOperationType and SnapshotTaskInputsBuildOperationType we can use the parent task id to link the events together and <a href="https://github.com/runningcode/gradle-doctor/blob/master/doctor-plugin/src/main/java/com/osacky/doctor/BuildOperations.kt#L62">calculate all the build cache keys for all the tasks which were just executed.</a></p><pre>val cacheKeys = mutableListOf&lt;String&gt;()<br>executeTaskIdsMap.entries.<em>forEach </em><strong>{ </strong>(operationId, task) <strong>-&gt;<br>    </strong>if (task.wasExecuted()) {<br>        val cacheKey = snapshotIdsMap[operationId].<em>hashByte</em><br>        cacheKeys.add(cacheKey)<br>    }<br><strong>}</strong></pre><p>Above is the code snippet that returns a list of build cache keys for all executed tasks in the project.</p><h4>Find all recently-added artifacts in the build cache</h4><p>The Gradle build cache is located by default in your Gradle user home in a folder called caches/build-cache-1 .</p><p>The build cache artifacts are stored in a compressed format in this directory with the build cache key as the file name.</p><p>The size of a compressed artifact for a task with a build cache key of ef41ae2ece5d is simply the following code in kotlin:</p><pre>File(&quot;caches/build-cache-1&quot;, &quot;ef41ae2ece5d&quot;).length()</pre><h4>Sum their size</h4><p><a href="https://github.com/runningcode/gradle-doctor/pull/52/files#diff-56ce9c2486f61d16179464c88b2b5168R47">We can sum the size of the compressed artifacts as follows:</a></p><pre>val cacheSizeBytes = cacheKeys.<em>sumBy </em><strong>{ cacheKey -&gt;<br>    </strong>File(cacheDir, <strong>cacheKey</strong>).length().toInt()<br><strong>}</strong></pre><h4>Calculate minimum remote build cache connection speed</h4><pre>val minimumConnectionSpeed = cacheSizeBytes / buildExecutionTime</pre><p>In part 3 of this series we’ll do some in depth calculations based on real world data and see whether certain tasks are better to store remotely than others.</p><h3>Try it out yourself</h3><p>Instead of doing all this work yourself, I’ve automated it for you in the <a href="https://github.com/runningcode/gradle-doctor">Gradle Doctor plugin</a>. To find out if a remote build cache is worth using on your internet connection run any gradle task with -PbenchmarkRemoteCache.</p><pre>./gradlew :app:assembleDebug -PbenchmarkRemoteCache</pre><p>You’ll get a nice report like the one below:</p><pre>=================Gradle Doctor Prescriptions========================<br>= Remote Build Cache Benchmark Report =<br>Executed tasks created compressed artifacts of size 159,93 MB<br>Total Task execution time was 208,85 s</pre><pre>In order for a remote build cache to save you time, you would need an internet connection to your node of at least 0,77 MB/s.<br>Check a build scan to see your connection speed to the build cache node.<br>Build cache node throughput may be different than your internet connection speed.</pre><pre>A 1 MB/s connection would save you 48,92 s.                                      A 2 MB/s connection would save you 128,88 s.               <br>A 10 MB/s connection would save you 192,86 s.<br>                                                                                                Note: This is an estimate. Real world performance may vary. This estimate does not take in to account time spent decompressing cached artifacts or roundtrip communication time to the cache node.   ====================================================================</pre><p>Let me know how it works for you and your workload. Is using the remote build cache worth it?</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1bc2b171f19" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How fast does my internet need to be to use the Gradle Remote Build Cache? (Part 1)]]></title>
            <link>https://medium.com/swlh/how-fast-does-my-internet-need-to-be-to-use-the-gradle-remote-build-cache-part-1-4acaa6f9a2fa?source=rss-85419ad6ecd1------2</link>
            <guid isPermaLink="false">https://medium.com/p/4acaa6f9a2fa</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[gradle]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[working-from-home]]></category>
            <dc:creator><![CDATA[Nelson Osacky]]></dc:creator>
            <pubDate>Fri, 03 Apr 2020 08:20:03 GMT</pubDate>
            <atom:updated>2020-04-23T23:37:25.153Z</atom:updated>
            <content:encoded><![CDATA[<p>Is it worth downloading artifacts from a remote build cache node on a slow internet connection?</p><p>This question is becoming ever more important as we all switch from our blazing fast office internet connections to our home internet connections.</p><p>This is part 1 of a 3 part series. <a href="https://medium.com/@runningcode/how-fast-does-my-internet-need-to-be-to-use-the-gradle-remote-build-cache-part-2-1bc2b171f19">Part 2 is now published.</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/281/1*wMcaNS6A6T1EkC34YLU3pA@2x.png" /></figure><h3>Downloading a Single Task</h3><p>How do we know if a remote build cache is worth it? Let’s take a simple Gradle task and calculate whether having a remote build cache is worth it.</p><p>If a task takes 10 seconds to execute and generates 1 MB of output, you would need an internet connection faster than 0.1 MB/s in order to save time. An internet connection of 1MB/s would mean that you could download the output of the task in 1 second, saving you 9 seconds of execution time.</p><h3>Calculation for a real Gradle task</h3><p>To do this for a Gradle task, you can print its outputs by adding the following to your build.gradle file:</p><pre>tasks.named(&quot;compileDebugKotlin&quot;).configure {<br>  outputs.files.forEach {<br>    println(it)<br>  }<br>}</pre><p>For the KotlinCompile task, the outputs are placed in that module’s build/tmp/kotlin-classes directory.</p><pre>$ du -sh libs/analytics/build/tmp/kotlin-classes/<br> 136K</pre><p>This KotlinCompile task produces 136KB of output and takes about 5 seconds to run on my computer. This would require a build cache connection of 0.136MB/5s = .0272 MB/s in order to be able to download the task faster than it would take to run locally.</p><p>The download size is actually smaller than 136KB because <strong>Gradle compresses artifacts before placing them in the build cache</strong>. This speeds up download time but adds decompression time. We’ll dive in to this later.</p><h3>Let’s check a build scan</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nb7nDTShrD6dLThtGYz4ag.png" /><figcaption>The build scan says we avoided 15.89 seconds. However, it only takes 5 seconds to run the task locally.</figcaption></figure><p>A build scan will tell us exactly how much time we saved by reusing the outputs of the task from the build cache. There is one caveat, <strong>it uses the amount of time that it took to run the task on a different machine when the remote build cache was seeded</strong>. In this case, the build cache was seeded from a significantly slower machine. This task only takes 5 seconds to run on my machine, but took 15 seconds when seeding the cache. To get a more accurate estimate, we need to estimate the minimum connection speed based on the local machines power.</p><h3>Calculating parallel computation</h3><p>Machines these days can perform multiple Gradle tasks at once. To perform the same calculation for two tasks run in parallel, we just take the length of the overall build, and divide it by sum of the two task’s outputs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/351/1*pmY9v9wabttpQYWLUuTS1A.png" /><figcaption>With two CPUs, we can produce twice the output in the same amount of time.</figcaption></figure><p>If two 10 second tasks run in parallel, the length of the overall build would still be 10 seconds. If both tasks produce 1MB of output, the sum of the two task’s outputs would be 2MB.</p><p>2MB/10s = 0.2MB/s minimum connection speed</p><p>The more tasks our local machine can run in parallel, the faster our connection to the build cache node needs to be!</p><h3>Compression</h3><p>Gradle compresses artifacts before storing them in the build cache. In the case of the above KotlinCompile task, the compressed artifacts are only 20KB instead of 136KB. This means our minimum connection speed to make the build cache worth it is much lower: 0.02MB / 5 seconds = 0.004 MB/s. This assumes the artifact decompression time is insignificant.<br>To calculate the size of the compressed artifact, we need to know the build cache key. We find this in the build scan by clicking on the task.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xCkftv12ewWaNDxiH9c7Uw.png" /></figure><p>The build cache stores artifacts by default in the ~/.gradle/caches/build-cache-1 directory where the name of the file is the build cache key, for example:</p><pre>du -h ~/.gradle/caches/build-cache-1/b59e646b297605c55f49a251bdd7814<br> 20K</pre><h3>Calculating a typical build</h3><p>We want to know if the build cache is worth it in a real scenario like assembling our app. To make this calculation, we would divide the amount of time a build would take by the total amount of compressed artifacts that the build produces. For the build time, we should only include the execution phase of the Gradle build. We exclude configuration time since <strong>tasks are neither executed nor downloaded </strong>during that time.</p><p>We run into a bit of a problem when trying to find the total size of all the compressed build cache artifacts. A Gradle build may run hundreds if not thousands of tasks. There is no public API to get the build cache key for a Gradle task. The only way to find the cache key is to manually look at a build scan. If we had to do that for 1000 tasks, we would be here all day.</p><p>In order to provide a real estimate, we will dive in to the internals of Gradle in <a href="https://medium.com/@runningcode/how-fast-does-my-internet-need-to-be-to-use-the-gradle-remote-build-cache-part-2-1bc2b171f19">part 2 of this post</a>.</p><p>If you want to run an automatic estimation in your project, apply the <a href="https://github.com/runningcode/gradle-doctor">Gradle Doctor plugin</a>. Then simply run any gradle task with -PbenchmarkRemoteCache.</p><pre>./gradlew :app:assembleDebug -PbenchmarkRemoteCache</pre><p>You’ll get a nice report like the one below:</p><pre>=================Gradle Doctor Prescriptions========================<br>= Remote Build Cache Benchmark Report =<br>Executed tasks created compressed artifacts of size 159,93 MB<br>Total Task execution time was 208,85 s</pre><pre>In order for a remote build cache to save you time, you would need an internet connection to your node of at least 0,77 MB/s.<br>Check a build scan to see your connection speed to the build cache node.<br>Build cache node throughput may be different than your internet connection speed.</pre><pre>A 1 MB/s connection would save you 48,92 s.                                      A 2 MB/s connection would save you 128,88 s.                <br>A 10 MB/s connection would save you 192,86 s.<br>                                                                                                Note: This is an estimate. Real world performance may vary. This estimate does not take in to account time spent decompressing cached artifacts or roundtrip communication time to the cache node.   ====================================================================</pre><p>Let me know how it works for you and your workload. Is using the remote build cache worth it?</p><p>Thank you to <a href="https://medium.com/u/75e0ff011233">Júlio Zynger</a> for proofreading this post.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4acaa6f9a2fa" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/how-fast-does-my-internet-need-to-be-to-use-the-gradle-remote-build-cache-part-1-4acaa6f9a2fa">How fast does my internet need to be to use the Gradle Remote Build Cache? (Part 1)</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Is building from the terminal faster than Android Studio?]]></title>
            <link>https://medium.com/@runningcode/is-building-from-the-terminal-faster-than-android-studio-175ead7dc2ca?source=rss-85419ad6ecd1------2</link>
            <guid isPermaLink="false">https://medium.com/p/175ead7dc2ca</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[gradle]]></category>
            <dc:creator><![CDATA[Nelson Osacky]]></dc:creator>
            <pubDate>Sat, 28 Sep 2019 09:14:31 GMT</pubDate>
            <atom:updated>2019-10-01T14:55:57.601Z</atom:updated>
            <content:encoded><![CDATA[<p>A couple people have sworn to me that building from command line is faster than building from Android Studio. I have also heard that Android Studio is faster than command line. Can this really be true?</p><p>This blog post dives in to a few reasons why builds might behave differently in Android Studio vs the terminal.</p><h3>Injected Properties</h3><p>Android Studio build is built with Gradle just like any other build. But it adds some additional information to each build by injecting some special <a href="https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties">project properties</a>.</p><p>You can see all the properties that are injected by Android Studio by adding the following to your build.gradle.</p><pre>for (def prop : project.properties) {<br>  if (prop.key.startsWith(&#39;android.injected&#39;)) {<br>    println(prop)<br>  }<br>}</pre><p>This will yield the following properties when invoked from the IDE.</p><pre>android.injected.invoked.from.ide=true<br>android.injected.build.abi=x86<br>android.injected.build.density=420dpi<br>android.injected.build.api=28</pre><p>android.injected.invoked.from.ide=true</p><p>This property is set to true when running a build from the IDE. The property does not exist when running from the terminal. You can use this to tag your build scans.</p><pre>buildScan {<br>  if (project.hasProperty(&quot;android.injected.invoked.from.ide&quot;)) {<br>   tag &#39;AndroidStudio&#39;<br>  } else {<br>   tag &#39;Cmd&#39;<br>  }<br>}</pre><p>If you don’t use build scans, you can send this information to whatever tool you use to keep track of build speeds in order to determine if Android Studio builds are faster than terminal builds for your project.</p><p>The Android Gradle Plugin (AGP) looks at the other properties to try to avoid unnecessary work and optimize the build.</p><p>android.injected.build.abi=x86</p><p>If you have native libraries (C/C++), theExternalNativeBuildTask in AGP will read the injected ABI property to skip building unnecessary binaries. In this caseandroid.injected.build.abiis set to =x86 so we skip building binaries for ARM.</p><p>android.injected.build.api=28</p><p>Using the injected API property, in this case 28, the Android Gradle Plugin can make dexing optimizations for Instant Run. This property is used in InstantRunPatchingPolicy. AGP can use a faster patching policy if the target device is using ART instead of Dalvik.</p><p>Even if Instant Run isn’t running, AGP can upgrade from legacy multi-dex to native multidex in TaskManager if the project’s min sdk &lt; 21 but the targeted device’s min SDK &gt; 21.</p><pre>// Upgrade from legacy multi-dex to native multi-dex if possible when using with a device<br>if (dexingType == DexingType.LEGACY_MULTIDEX) {<br>    if (variantScope.getVariantConfiguration().isMultiDexEnabled()<br>            &amp;&amp; variantScope<br>                            .getVariantConfiguration()<br>                            .getMinSdkVersionWithTargetDeviceApi()<br>                            .getFeatureLevel()<br>                    &gt;= 21) {<br>        dexingType = DexingType.NATIVE_MULTIDEX;<br>    }<br>}</pre><p>android.injected.build.density=420dpi</p><p>Using the density property, AGP find the right split APK by screen density in SplitOutputMatcher. A smaller APK will strip out unnecessary resources in order to reduce APK transfer and installation time.</p><h3>Instant Run</h3><p>Android Studio also injects a special property when invoking Instant Run.</p><pre>android.optional.compilation=INSTANT_DEV</pre><p>This property is defined in the enumOptionalCompilationStep. AGP will use the Instant Run mode optimized for the target device’s SDK version by looking at the android.injected.build.api injected property.</p><p>Instant Run disables <a href="https://docs.gradle.org/current/userguide/build_cache.html">Gradle’s build cache</a>. Gradle’s build cache stores the outputs of tasks and builds to reuse them later and avoid rebuilding things which are already built. Instant run completely ignores the Gradle build cache. Because of this, building from the IDE and switching branches means you could end up spending a lot of time rebuilding.</p><p>I would dive deeper in to Instant Run, but I think it isn’t worth spending too much time on since it was removed in Android Gradle Plugin 3.5.0. You won’t have to worry about it slowing down your build anymore.</p><p>If you are using Android Gradle Plugin 3.4.0, you can ensure that your fellow developers are not plagued by slow or inconsitent Instant Run builds by adding the following code to your build.gradle:</p><pre>def instantRun = project.getProperties().get(&quot;android.optional.compilation&quot;)?.contains(&quot;INSTANT_DEV&quot;)</pre><pre>if (instantRun) {</pre><pre>  throw new IllegalStateException(&quot;Disable Instant Run: Android Studio -&gt; Preferences -&gt; Build, Execution, Deployment -&gt; Instant Run&quot;)</pre><pre>}</pre><h3>Built-in JDK</h3><p>Android Studio comes bundled with a JDK and uses it by default. Your terminal is likely pointed to a different JDK installation. A different JDK makes the Gradle Daemon incompatible between Android Studio and the terminal which breaks incremental compilation. If you notice really slow builds when switching back and forth it might be caused by this incompatibility.<br>To test for the incompatibility you can switch from Android Studio to the terminal. If you see the following message you may have an incompatibility.</p><p>Starting a Gradle Daemon, 1 incompatible and 0 stopped Daemons could not be reused, use — status for details</p><p><a href="https://medium.com/u/2ecb8c645081">Svyatoslav Chatchenko</a>’s <a href="https://medium.com/@mydogtom/tip-how-to-reuse-gradle-daemon-between-android-studio-and-terminal-df5232d63f38">post covers how to make your Daemon compatible.</a></p><p>The instructions have changed a bit for Android Studio 3.5.0. You need to open Project Structure -&gt; SDK location.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9oDOhy6FuzmVSXVNx-GNcQ.png" /></figure><p>You can ignore the message that says “To use the same Gradle daemon…select JAVA_HOME.” In Android Studio 3.5.0, this will not work.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GeCjoWBfDXBTIjCLFNBGUg.png" /><figcaption>JDK Location</figcaption></figure><p>When you open the dropdown, selecting the JAVA_HOME option will give you the same JDK location as the embedded JDK. This is a <a href="https://issuetracker.google.com/issues/140220674">known issue in Android Studio</a>.<br>Because of this bug, you’ll need to copy paste your JAVA_HOME in the setting. You can obtain your JAVA_HOME with the following command:</p><p>echo $(/usr/libexec/java_home)</p><p>Once you have entered your JAVA_HOME you shouldn’t get an error message indicating that the Gradle Daemons are incompatible when switching between Android Studio and the terminal. If you still get incompatibilities, <a href="https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:why_is_there_more_than_one_daemon_process_on_my_machine">you can find more information on how to debug it here.</a></p><h3>Which is faster?</h3><p>I didn’t really answer the question of which is faster. The thing is, depending on the project configuration, the size of the project, and many other factors one might be faster than the other. It’s important to minimize the differences to ensure consistent builds. It’s also important to measure build speeds. These are just a few differences between building from Android Studio and the terminal. There may be more and things have changed in Android Studio 3.5.</p><p>At SoundCloud, builds from the terminal and Android Studio for the assembleDebug task in our main app were both just about 58 seconds on average in the last 28 days.</p><blockquote>Edit: A couple people have pointed out that this is a clickbait-y title and I didn’t provide sufficient metrics in this post. Thank you for challenging me. It made me realize that even the assembleDebug metrics I provided don’t capture the full picture. Ideally we should also measure app install time because Instant Run optimizes the installation process by stripping out unnecessary pieces from the APK. However we cannot compare installDebug in this case because Android Studio doesn’t use the installDebug task. It instead installs the APK by directly calling ADB. This makes it a bit more difficult to compare the two builds. If anyone has thoughts or ideas on how to better measure this, please let me know. I’ll keep digging.</blockquote><p>Thanks to <a href="https://medium.com/u/3435eb04e779">Tom Sammons</a> for inspiring and proofreading this post.<br>Thanks to <a href="https://medium.com/u/bd07c15cab26">John Rodriguez</a> for <a href="https://gist.github.com/jrodbx/eaa1fed6d958fc6eb23f10a75fe3f125">this gist</a> to easily examine AGP sources and also proofreading this blog post.</p><p>Need some help improving Gradle build speeds? <a href="https://osacky.com">I’m available for help</a>!<br>Did I help improve your build speed? <a href="https://www.buymeacoffee.com/ZwCQiFYkb">Buy me a chocolate</a>. nom nom</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=175ead7dc2ca" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Testing new versions of the Android Gradle Plugin]]></title>
            <link>https://medium.com/@runningcode/testing-new-versions-of-the-android-gradle-plugin-ea80df978316?source=rss-85419ad6ecd1------2</link>
            <guid isPermaLink="false">https://medium.com/p/ea80df978316</guid>
            <category><![CDATA[gradle-plugin]]></category>
            <category><![CDATA[gradle]]></category>
            <category><![CDATA[gradle-speed]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Nelson Osacky]]></dc:creator>
            <pubDate>Wed, 07 Aug 2019 14:35:30 GMT</pubDate>
            <atom:updated>2019-09-29T13:30:02.613Z</atom:updated>
            <content:encoded><![CDATA[<p>Here’s how to test new versions of the Android Gradle Plugin while shipping your app with a stable version. You can use this pattern to test any new version of a Gradle plugin or a library. This is a great way to allow developers to use new build performance features and IDE improvements in the Android Gradle plugin while simultaneously shipping your app with a stable version of the Android Gradle Plugin.</p><p>First we can define a boolean in our Gradle build script.</p><pre>def useAgpRC = (project.properties[&#39;useAgpRC&#39;] ?: &#39;false&#39;).toBoolean()</pre><p>This sets the property disabled by default. Use true instead to enable it by default.</p><p>You can enable the property by running a build with -PuseAgpRC=true</p><p>You can also add useAgpRC=true to your gradle.properties.</p><p>Individual developers on your team can opt in by adding useAgpRC=true to ~/.gradle/gradle.properties.</p><p>This special Gradle Properties file affects all Gradle projects on your machine but has a lower precendence than the gradle.properties in the project.</p><p>When enabled, we switch to use the Android Gradle Plugin 3.5 Release Candidate.</p><pre>if (useAgpRC) {<br>  classpath &#39;com.android.tools.build:gradle:3.5.0-rc02&#39;<br>} else {<br>  classpath &#39;com.android.tools.build:gradle:3.4.2&#39;<em><br></em>}</pre><p>This is what our buildscript dependency block looks like putting all that together.</p><pre>buildscript {</pre><pre> dependencies {</pre><pre>  def useAgpRC = (project.properties[&#39;useAgpRC&#39;] ?: &#39;false&#39;).toBoolean()</pre><pre>  // To enable AGP 3.5 add `useAgpRC=true` to your<br>  // `~/.gradle/gradle.properties`.</pre><pre>  if (useAgpRC) {<br>    println(&#39;Using AGP 3.5 RC&#39;)<br>    classpath &#39;com.android.tools.build:gradle:3.5.0-rc02&#39;<br>  } else {<br>    println(&#39;Using AGP 3.4 Stable&#39;)<br>    classpath &#39;com.android.tools.build:gradle:3.4.2&#39;<em><br>  </em>}<br>}</pre><p>If you are using the Gradle Remote Build Cache and seeding it on CI machines. Make sure to seed the cache with -PuseAgpRC=true and -PuseAgpRC=false.</p><p>If using Build Scans, you can also tag your build with</p><pre>buildScan { <br>  value &quot;AGP RC&quot;, useAgpRC.toString() <br>}</pre><p>Was that cool? <a href="https://www.buymeacoffee.com/ZwCQiFYkb">Fund my chocolate addiction.</a></p><p><a href="http://www.osacky.com">I’m also available for Gradle help.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ea80df978316" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Upgrading to the new HasAndroidInjector in Dagger 2.23]]></title>
            <link>https://medium.com/@runningcode/upgrading-to-the-new-hasandroidinjector-in-dagger-2-23-318f8ca35b2b?source=rss-85419ad6ecd1------2</link>
            <guid isPermaLink="false">https://medium.com/p/318f8ca35b2b</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[dagger]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[dependency-injection]]></category>
            <dc:creator><![CDATA[Nelson Osacky]]></dc:creator>
            <pubDate>Fri, 31 May 2019 13:39:40 GMT</pubDate>
            <atom:updated>2019-09-29T13:17:16.598Z</atom:updated>
            <content:encoded><![CDATA[<h3>Reducing Boilerplate with the new HasAndroidInjector in Dagger 2.23</h3><p>Dagger 2.23 introduces the HasAndroidInjector interface. It reduces some boilerplate in your Application class. Here is how you can <em>destroy</em> some of that boilerplate.</p><p>You might have an Application class that looks like this:</p><pre>class MyApplication : Application(), HasActivityInjector, HasServiceInjector, HasBroadcastReceiverInjector, HasSupportFragmentInjector</pre><p>And therefore you will also have some of these:</p><pre>@Inject lateinit var androidActivityInjector : DispatchingAndroidInjector&lt;Activity&gt;</pre><pre>@Inject lateinit var androidFragmentInjector : DispatchingAndroidInjector&lt;Fragment&gt;</pre><pre>@Inject lateinit var androidBroadcastReceiverInjector : DispatchingAndroidInjector&lt;BroadcastReceiver&gt;</pre><pre>@Inject lateinit var androidServiceInjector : DispatchingAndroidInjector&lt;Service&gt;</pre><p>And you also have to implement those Has*Injector interfaces like so:</p><pre>override fun activityInjector(): AndroidInjector&lt;Activity&gt; = androidActivityInjector</pre><pre>override fun serviceInjector(): AndroidInjector&lt;Service&gt; = androidServiceInjector</pre><pre>override fun broadcastReceiverInjector(): AndroidInjector&lt;BroadcastReceiver&gt; = androidBroadcastReceiverInjector</pre><pre>override fun supportFragmentInjector(): AndroidInjector&lt;Fragment&gt; = androidFragmentInjector</pre><p>With Dagger 2.23, you can replace those 4 interfaces with just one:</p><pre>class DaggerExampleApplication : Application(), HasAndroidInjector</pre><p>And instead injecting 4 different injectors, you can just inject one:</p><pre>@Inject lateinit var androidInjector : DispatchingAndroidInjector&lt;Any&gt;</pre><p>Now you just have one method to implement:</p><pre>override fun androidInjector(): AndroidInjector&lt;Any&gt; = androidInjector</pre><p><a href="https://github.com/runningcode/dagger-upgrade/commit/61734382d554b29534371d8977caa78e3429de4a">Check out this sample commit performing this boilerplate reduction</a>.</p><p>If you already extend from DaggerApplication, you will not need to make any changes.</p><p><a href="https://github.com/google/dagger/releases/tag/dagger-2.23">Click here for the rest of the Dagger 2.23 release notes.</a></p><p>Thanks to the Dagger team for incorporating the feedback that dagger has a lot of boilerplate and setup!</p><p>P.S. Use Dagger 2.24 is the latest version.</p><p>Did I help save you some time? <a href="https://www.buymeacoffee.com/ZwCQiFYkb">Fund my chocolate addiction</a>.<br><a href="https://osacky.com/">I’m also available for Gradle help</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=318f8ca35b2b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>