I have a project with 30+ modules and sub modules(feature base modules).
I've read that build time of a multi module project is less than a single module project, as it was when it had less than 10 modules(Layer base modules). But when module count grows it affects Android Studio index/build/sync time. Moreover, during development of a multi module project Android Studio takes high CPU and Memory usage.
What should I do to optimize build speed and Android Studio performance?
Note 1: There is a complex relation between module dependencies.
Note 2: Gradle parallel has been enabled and I've checked Google Optimize your build speed
I was having the same issue as yours. I solved my problem by using custom gradle dependency resolution.
The idea is pretty simple, I publish all my modules to a repository (artifactory in my case) and then in my build.gradle file for modules I depend on the published modules. To switch the dependency from published to local during development I use gradle dependency resolution to resolve to local versions.
def loadedModules = [:]
getSubprojects().forEach {
loadedModules.put(it.name, it.path)
}
def group = 'np.com.susanthapa.efficientmultimodule'
allprojects {
repositories {
mavenLocal()
google()
jcenter()
// replace configurations for all modules
configurations.all {
// get our own dependencies
resolutionStrategy.dependencySubstitution.all { dependency ->
if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.group == group && loadedModules.containsKey(dependency.requested.module)) {
def targetProject = findProject(loadedModules.get(dependency.requested.module))
if (targetProject != null) {
dependency.useTarget targetProject
}
}
}
}
}
}
Then what you can do is unload all the modules from your project except app module and also comment out all the modules from settings.gradle file.
Now to work on a particular module just uncomment that specific module in settings.gradle and also load that module in android studio. The above code will make sure that the local version of the loaded module will be used through out your project. This should reduce the build time as well as android studio indexing.
For more info here is the link to the blog post.
Follow the profiling steps in the link you posted.
In addition or for quicker/less formal profiling you can use the --scan option with a ./gradlew build and check the stats that are published online.
Memory usage can be tuned based on those results and that can give you great benefits. Personally, I've seen builds take literally minutes in garbage collection due to low memory.
You can also increase the memory available to Android Studio based on these results. Help->Edit custom VM options. But I would get to the point you are seeing improvements on the command line (./gradlew) builds first.
Related
My project has more than 10+ maven repositories in the build.gradle, and the denpendencies speicified in my projoect are about 100 or more. This causes a problem. Each time I sync the gradle, it would try each maven repository for each dependency until it finds one providing that module.
The gradle docs contain the following:
A project can have multiple repositories. Gradle will look for a dependency in each repository in the order they are specified, stopping at the first repository that contains the requested module.
However, this is really time-consuming. How can I speed up this process? Can I give some hint for a denpendency using some repository, avoid trying each one blindly?
I have an Android project that has around 15 modules each of them is a separate GitHub project, some of the modules have interdependencies, its basically a sample client with a library that has 14 components(modules).
Every time I make a single change and re build/run it takes takes about 1 min 40 seconds on an i7 with 28GB Ram
I have tried many things to improve the build time, including the tips in this article,But I have not seen a significant change.
https://medium.com/#erikhellman/boosting-the-performance-for-gradle-in-your-android-projects-6d5f9e4580b6
it looks like it goes through all the modules and see if they are Up to Date, which takes time, but also compiling and the dexing.
Does any one have an idea on how to improve this?
I am using Gradle plugin 1.2.3, BuildTools 22.0.1 and TaskWrapper 2.4
I was suffering from the same problem before but as google announced in there last I/O that there is a big improvement in performance in Gradle and android studio in common.
but for me this single trick helps me a lot and reduce the time by more than 50%.
make Gradle run offline.
The next official planned release of Gradle plugin is 1.3. If you watch the talk on gradle from a presentation at Google I/O https://youtu.be/f7ihSQ44WO0?t=4m23s then Google are making claims of big performance improvements. If these claims prove to be true then I believe that this will be the best chance of cutting down build times for Android projects.
Currently you can use the latest beta version which is
1.3.0-beta4 by adding it to your build.gradle file. Example below:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0-beta4'
}
}
allprojects {
repositories {
jcenter()
}
}
Checking for any new beta versions can be done at jcenter https://jcenter.bintray.com/com/android/tools/build/gradle/
If you don't need that all dependency update every time you run your project, I suggest you to configure gradle to work offline. You can do that in Android Studio in the Gradle tab in the Setings windows. I hope that this can help you.
I just developed a JavaFx application which use RXTX library for serial communication and in the future will use Bluecove for bluetooth. It was my understanding that there are some ways to run a JavaFx app on Android devices, so I began my research.
The first option was running the "jar" packaged app with the Android app "Java Manager". The problem here is that I wouldn't know what to do with the external libraries, since there isn't a standard JVM on the android devices where I could place them.
I found this project "http://v-lad.org/projects/gnu.io.android/", but it seems it's oriented to Android applications.
So when I found "http://javafxports.org/", I tried to make my first steps with it. This project seems to be what I need, but I'm a newbie in Android and I find documentation a little bit confusing, so I'm not sure where to start. Moreover, I'm still not sure that I could use those java libraries in Android with this approach.
Does anyone know if what I pretend is doable?? In that case, which steps should I follow??
You can already try JavaFXPorts plugin. It's in continuos development, but the recent versions are mature enough to use it without problems.
Have a look at the basic requirements to get started here. You will need JDK8u40+, Gradle 2.2+, Android SDK and Android Build tools.
Once you have everything ready, you can try the samples.
Also I suggest you have a look at Gluon-plugin for NetBeans. Basically it will create a new empty JavaFX project for you, and you will be able to build it and deploy it on your desktop, on Android and on iOS platforms.
Have a look at the build.gradle file:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.0.0-b4'
}
}
apply plugin: 'org.javafxports.jfxmobile'
repositories {
jcenter()
}
mainClassName = 'org.test.javafxports.TestJavaFX'
jfxmobile {
ios {
forceLinkClasses = [ 'org.test.javafxports.**.*' ]
}
}
First of all, you just need to update the plugin version. Check here for the last one: 1.0.0-b8.
Build and run on your desktop, or run the tasks like androidInstall to generate the apk and deploy it on your Android mobile.
Once you have tested it, and everything is working properly, you can start adding the code of your project.
And back to your question, yes, you can add any third party jar to the project.
Basically you just need to add the dependency on the gradle file. You can use compile or runtime with local files or from external repositories:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.0.0-b8'
}
}
apply plugin: 'org.javafxports.jfxmobile'
repositories {
jcenter()
}
dependencies {
compile files('lib/<your local jar>.jar')
compile 'org.glassfish:javax.json:1.0.4'
androidCompile 'org.glassfish:javax.json:1.0.4'
}
mainClassName = 'org.test.javafxports.TestJavaFX'
jfxmobile {
ios {
forceLinkClasses = [ 'org.test.javafxports.**.*' ]
}
}
Note you can add dependencies that only are added to one single platform, like androidCompile or androidRuntime.
Since the apk will run on Dalvik VM, only Java 7 features are allowed. You can use lambdas, though, since the plugin uses Retrolambda project internally on your code. Be aware that it is not applied on the added jars.
As an example of using jars on your project, you can use Gluon-Charm-Down open source library, that already provides access to some native services on your device, like local storage or GPS.
dependencies {
compile 'com.gluonhq:charm-down-common:0.0.1'
androidRuntime 'com.gluonhq:charm-down-android:0.0.1'
desktopRuntime 'com.gluonhq:charm-down-desktop:0.0.1'
}
In fact, with jfxmobile plugin and this library, the 2048FX game has been successfully ported to Android (Google Play) and iOS (Apple Store).
I already saw this question, but it is not helping me. First of all, I tried to add google play services in my project using:
dependencies{
compile 'com.google.android.gms:play-services:6.5.87'
}
It was showing me error:
Then I updated my studio to 1.0.1 and gradle to 1.0.0. And then I again synced the project with gradle. And it worked! It showed me another option despite of two options shown in above screenshot. It was "Install the library"(something like that). I clicked it and it popped up a dialog, and I installed the library(it was like downloadind using SDK manager and not like gradle downloads).
Now, I tried to download this library using:
compile('com.fortysevendeg.swipelistview:swipelistview:1.0-SNAPSHOT#aar') {
transitive = true
}
And it gives me error:
My android repository is updated:
Also, my internet connection is working fine. I tried to sync project many times, but same error all the time. I am not running gradle in offline mode:
How to fix this? And what is the permanent solution? And why is all this happening?
I found this question: Studio failed to download library from gradle repository which describes the exact same error, and that question had this bit of build script that you need to add to the build file that has the dependency statement in question:
repositories {
maven { url 'http://clinker.47deg.com/nexus/content/groups/public' }
}
When I do this, it works for me.
As to the general question of why this happens (and the better question of why the solution is different for different libraries):
Gradle, the build system that Android Studio uses, has the ability to automatically download library dependencies from the Internet. By and large this is a big boon for developers, because instead of having to manually download archive files, put them in the right place in your project, check them into source control, and repeat the process for new versions, now you just have to add a line of build script and the build system takes care of the housekeeping for you. The major downsides are Internet connectivity woes, which affect different developers to different degrees, and some added confusion about what it means when you get an error.
How does Gradle know where to download dependencies? Most Gradle build scripts contain a block that looks like this:
repositories {
jcenter()
}
or it may be mavenCentral() instead of jcenter(). This tells the build system to look in the JCenter or Maven Central global repositories (and JCenter is in a simplistic way of thinking about it a value-added mirror of MavenCentral); these contain archives of many versions of many, many, many libraries and are very convenient to use.
You can specify other repositories as well. This swipelistview library hasn't been uploaded to Maven Central, so the developer has made a repository for it available via a URL: if you add that URL to your repositories block, it will look for it there.
I was worried about the fact that you're accessing a SNAPSHOT version of the library -- these are supposed to be unpublished by definition. But adding a dependency on the snapshot version of the library in my test project worked for me, and looking around that URL in a web browser reveals that there's only a "1.0-" (trailing dash included) version of the library, so there's some subtletly there I'm missing; if you know more, please edit my answer or comment.
In any event, there are a couple caveats to this explanation. Some libraries aren't on Maven Central or on any Internet-accessible archive (at least they're not officially published by Android), but are instead published as part of the Android SDK download and maintained via the SDK manager. The Android support libraries and Google libraries fall under this category. If you get errors about those not being found, you have to fix it via the SDK manager.
How does the build system know to look in the SDK for those, since you didn't tell it via the repositories block? This behavior is hardcoded into the Android Gradle plugin.
The other caveat is that there's a detail that trips up a lot of people, which is that you actually have two repositories blocks, though with the usual Android Studio setup they're often in different files. One is in a buildscript block, which usually lives in the top-level build.gradle file and looks like this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
The other often also lives in the top-level build.gradle, but you can augment it with another block in your module's build.gradle file. The top-level one looks like this:
allprojects {
repositories {
jcenter()
}
}
and a module-level one would look like one of the previous examples in this answer. What do all of these mean?
The buildscript block tells Gradle where to find build system plugins. These are plugins that enhance the functionality of the build system itself but don't say anything about your actual project. In Android projects, the Android Gradle plugin is in this category, and unlike the Android/Google libraries, this one does live on Maven Central. The repositories block (in coordination with the dependencies block, which is not the same as the dependencies block for your project, keep reading) in buildscript tells the build system where to go look for these plugins.
The allprojects block in the top-level build file tells the build system to apply the bit of contained script to all build files in the project. In this example, it's telling it to add a repositories block pointing to JCenter to all subprojects. This is a convenience so you don't have to copy/paste it into multiple build files in your modules.
In your modules, you also have a repositories block, which in conjunction with the allprojects thingy, tells the build system where to go to get library dependencies for your project, as was previously discussed.
I want to have gradle intelligently use the most recent SNAPSHOT for a given dependency which is available.
Assuming i have a build file like this:
mavenCentral()
// if (gradle.startParameter.refreshDependencies == false) {
mavenLocal()
// }
maven {
url "my_local_repo.com
}
}
With a dependency listed like this:
compile (group: 'com.mystuff', name: 'my-library', version: '1.0.0-SNAPSHOT', changing: 'true')
Which may exist both in Maven Local and in the Remote repo "my_local_repo.com" how do I ensure that Gradle always compiles with the most recent snapshot?
My reading here:
http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
Specifically point 8.5:
A project can have multiple repositories. Gradle will look for a
dependency in each repository in the order they are specified,
stopping at the first repository that contains the requested module.
makes me believe that the mavneLocal version will always be preferred, however my reading of
51.7 here:
http://www.gradle.org/docs/current/userguide/dependency_management.html#sec:repositories
Given a required dependency, Gradle first attempts to resolve the
module for that dependency. Each repository is inspected in order,
searching first for a module descriptor file (POM or Ivy file) that
indicates the presence of that module. If no module descriptor is
found, Gradle will search for the presence of the primary module
artifact file indicating that the module exists in the repository.
...
Once each repository has been inspected for the module, Gradle will
choose the 'best' one to use. This is done using the following
criteria:
and 51.2.4
Alternatively, sometimes the module you request can change over time,
even for the same version. An example of this type of changing module
is a Maven SNAPSHOT module, which always points at the latest artifact
published. In other words, a standard Maven snapshot is a module that
never stands still so to speak, it is a “changing module”.
Muddies that substantially. It appears to say that all repo's are checked and the "best" choice is made (in this case presumably the most recent).
The bit I think you forgot to highlight from section 51.7 is this:
When the dependency is declared by a static version and a module descriptor file is found in a repository, there is no need to continue searching later repositories and the remainder of the process is short-circuited.
Which aligns with what is stated in section 8.5. But yes, for changing modules (ie. snapshots), Gradle will check every repo to find the latest artifact. For static modules, it will simply take the first one it finds.