After I installed MultiDex I noticed,first ever launch of the app takes extra 4-5 seconds. However after a few researches, I noticed that the app size inside the phone settings(app manager) went from 7 MB to 19 MB and if I clear data, app goes back to 7 MB. But every time that I launch the app for the first time, app size increases to more than double.
Now my question is, what happens that makes the app size increase so much?
So far I have found a few topics on slackoverflow about MultiDex but none talks about what really happen with the code, and what kind of data MultiDex saves/caches.
Multi-Dexing is enabled in your gradle and extended in your Application class.
This is used when you use over 64,000 methods.
https://developer.android.com/studio/build/multidex
I would say probably 90% of the time if you are hitting multi dex needs, you have likely not properly managed your dependencies. I'm NOT saying every time. However, typically the issue is people bring in entire Google dependencies instead of just the ones you need. For example the Google Play Services. If you include this, it will instantly force you into multi-dexing. However, this does come with a performance hit. You now have multiple dex files to load. There is some pre-dexing of course for things that will not change such as 3rd party dependencies to help your speed a bit on building and deploying. However, having multiple lookup tables comes with it's speed consequences. For example, if you included.
com.google.android.gms
has about 44,000 methods alone in it, You should specify which one you want like
com.google.android.gms:play-services-location:16.0.0
for example.
So before you go down the road of using Multi-Dex, ensure you have properly cleaned up your unused dependencies, and that you are properly managing your transitive dependency tree. Also don't forget to use ProGuard or the new D8 minification process as that may also help you, although may require you to run in Debug as well if you have that heavy of dependencies.
If you have done all that and you still need to use Multi-Dex (and I have run into this at larger companies that force tons of bloat libraries on you) then you go for it.
Now as for what is happening, well Dex stands for Dalvik Executable. It is the process of packaging the code into Dalvik bytes for execution. This is limited to 65,536 methods. They say 64k in the documentation, but everywhere I've read shows 65k+. Many of Google's libraries already contain 17k methods which puts you 1/4 of the way there right out the gate.
I believe the issue has something to do with the header allocation of 2 bytes per method signature and the lookup table. they are limited on number of unique IDs they can create. So it requires you to create multiple dex files with multiple lookup tables for the method signatures. So the short answer is, it makes multiple Dalvik Executable files to ensure unique method signatures are properly found and executed on the Dalvic Virtual Machine.
Other important things to note, is that prior to Android API 21, the Virtual Machine only supports 1 dex file. Therefore you need to do multi-dex install on your application onCreate to get the rest brought in properly. However, if you are using proguard, your additional dex files could have been removed so you may need to address a MultDexProguard file as well.
Now, it's important to realize that Android completely redid their Virtual Machine and no longer relies on Dex for their modern OS virtual machines. So then the next question is "should you still use it"?
Well if you are still needing to support pre-Lollipop, then you are better off leaving your multi-dex in place. Otherwise if you are Lollipop and up. Android uses ART (Android Runtime) and does not have this limitation. Honestly the population that has pre-Lollipop is so small that it is not worth supporting in my personal opinion, but it depends on your product and your needs.
Hope that helps shed some light on things here.
Happy Coding
A single .dex file can have 65,536 methods(references) so if the number of references exceeds 65,536, you go with multidex.
Maybe as your app is storing more than one .dex file it is allocating more space for new .dex files.
Breakdown your APK using APK Analyser to see what is causing the app size to increase
use the following link refer
https://developer.android.com/studio/build/apk-analyzer
if you want to decrease the size of the app this article is helpful
https://medium.com/exploring-code/how-you-can-decrease-application-size-by-60-in-only-5-minutes-47eff3e7874e
Related
this is not a technical question.
I'm asking this because I don't understand how can this (64k limit) be avoided.
Aren't a "fancy" app always over 64k methods when it keeps adding functions and features from time to time? Or is that means those 'fancy' apps are always multidex-ed?
64K indeed doesn't make any sense in the modern era with apps coming with large amount of features, advanced and complex architectures, large libraries(try the full suite of Google Play Services), and the said libraries doing code generation for us like what an DI library like Dagger can do, the Dalvik executable has the 64K limit because thats what its designed for the limit is on the number of methods that can be referenced not defined, so we opt for multidexing, by default I would say all debug flavours of an app should have multidexing because without proguard truncating and compressing and removing everything unnecessary out we will eventually hit the 64K limit, but quite often when generating the release variant we would and can quite possibly stay under the 64K limit.
So for your question any app that crosses the 64K limit even after proguard has to be multidexed regardless of whether its fancy or not.
These are a series of questions for Android Studio programmers who have worked on large projects before. So, before I list the questions let me explain why I'm asking.
I couldn't help but notice it taking 36+ seconds for Gradle to sync and build for me to start programming every time I launch AS. It's not so much a problem now, but how about when the project starts to get over 26,000+ lines of code? So, now my real questions are:
1) Do large projects take significantly longer for Gradle to sync and build than a small one?
2) If it does, are there any levels of refactoring/error catching that I could bypass in the sync/build to make the process faster in the long run?
3) My computer can run any game on full ultra quality. Is a system spec that makes compiling and programming language processing faster than a gaming spec?
Thanks to all who contribute, and you will be acknowledged (with at least a vote) regardless of whether you can answer all the questions or not!
Lucky you. Gradle speeds have increased considerably over the last two years. As of today, even though still a bit slow, I'm pretty satisfied with the speed. Anyhow. Regarding your questions, here's my two cents:
Yes. But it's not a linear "function". I haven't come across any project that takes more than 3 or 4 mins tops when configured correctly, one especially was pretty big.
The only way to "speed up" the process is to allocate more memory. There are two ways here, inside the inner (module) gradle file, you can do this:
dexOptions {
javaMaxHeapSize "5g"
}
Or you can define a field inside the gradle.properties file:
org.gradle.jvmargs=-Xmx5632M
There is no system spec that I know of that will increase performance, but sounds like you got a pretty good system and you will not run into any troubles. A lot of progress has been made in the field.
Enjoy developing.
Yes, larger projects will take longer to sync and build. Lines of code is a contributing factor, as well as dependencies, number of assets, etc. Gradle is also somewhat infamous for being a bit slow.
This is dependent on your individual Gradle configuration. Removing unneeded steps (if you have configured some), such as signing the APK, may also help. 'Instant Run' is very quick for small changes but is somewhat untrustworthy. There's no way to 'skip' steps of compilation - if a recompile is needed, a recompile is needed. Trust that the compiler and IDE will optimise out any unnecessary steps and ensure that you are not asking for any unnecessary extra steps.
Gaming computers generally have fairly beefy processors, which are the main component used to sync and build a project. The disk read speed of your hard drive will also be a factor - SSDs will be much faster than platter drives - but it's comparatively much less important than your processor. Your video card, the other big component in a gaming PC, will not be used at all to build. A solid gaming PC will be more than adequate for development.
There are a few ways to shave time off your Gradle build times (for example) but build times will always be a reality.
I am building some android application. And of course it use many library included in gradle.
I want to do performance test, which library can affect much my application performance for doing other logic , like encode and decode, or other stuff.
Any idea?
There's an entire section in the Android User Guide called Profile Your App. There's a number of tools you can use to measure the performance of your app, however an extensive performance testing will probably be time consuming. Normally you'd have to identify a problem in your app and pick appropriate profiling techniques to find out what causes it.
To add to #Egor's answer about profiling, you may also want to think about the method count limit when considering library dependencies, in particular on older devices. While not directly related to runtime performance, having to use multidex in your builds will significantly increase your build times and the initial loading time of your app (on Android older than Lollipop).
Recently I have read about the Dalvik 65K method limit. I have understood that the method invocation list can only invoke first 65536 method references.
To tackle this, we have a number of solutions. One of which being multidexing where we split the .dex files to number of classes [classes.dex, classes1.dex ...] by using Android's support library.
What I have failed to understand is: What drawback does an Android application suffer due to this multidexing and why should we put lots of effort in minimising the number of referenced methods?
Basically in my understanding, to reduce the method count, I have to reduce modularisation, which makes my code a bit less readable, leaving apart the number of hours burned in stripping down the code of third-party libraries. Is reducing the method count worth it?
You are overthinking about multidex, instead you should observe and identify if there is any performance issue with your app by profiling your application.
Multidexing hardly increases any size of code, major size and performance issues are with animation/image/audio/video resources, they are the ones who increase size and reduce performance.
Including many third party libraries will eventually pass 64k limit and almost all applications today are multidexed, Users demand multifeatured apps today, that requires integration with many third party libraries.
Only when you are doing animation/game programming, where speed matters the most, more method calls might be harmful, but this has nothing to do with multidexing, even poorly written small non multidexing app will perform bad on any device.
Startup time will affect with multidexing, but it can certainly be improved by changing your app logic to delay loading of other costly library and resources.
Is reducing the method count worth it??
NO
Ideally you should use more methods and modularize your code, because testing and changing mobile apps is huge challenge after it is published. Debugging and removing bugs are more costly then multidex size and its impact on performance. Due to tiny screens, different brands, different UI, users get more angry on apps on phone compared to computers. Keeping up to users demand will become easier if code is divided into multiple individual tested libraries.
The main drawback is a larger dex/apk size. Dex files have pools of constants that are shared among all the classes in that dex file. When classes are split across multiple dex files, these shared constants have to be duplicated in each dex file they are used in.
Multidexing itself is non-performing term, if application is multidex it means there is burden over android internal process which executes application.
Every android application runs inside a single process(task), when its multidexed, it means the process is divided into parts which going to create performance issues with small android processor, no matter how you write code.
I am agree with aakash kava that almost all applications are multidexed because now a days android processors are very good in performance and android RAM is excellent, But it does't ,mean we should ignore multidexing.
Generally spoken the disadvantages of multidex are: Increased APK size, possibly slower app startup and increased memory footprint.
The reason for that is that some data (e.g. StringData) can not be shared and therefore need to be partially stored in multiple DEX files at the same time. StringData consists of string literals loaded from code as well as class, method and field names and commonly account for up to 20% of the total DEX file.
But the actual disadvantages (beside APK size) highly depend on the Android version you are running the app on.
Google optimized the Android Runtime (ART) to remove these drawbacks. Android O (API 26) introduced the VDEX container to store pre-validated DEX files. With Android P Google further optimized the precompiler (codename CompactDex) and added an shared data section to the VDEX container to deduplicate the data used in multiple DEX files. So there are little to none disadvantage when running multidex apps on Android P runtime.
Sources: What's new in Android Runtime (Google I/O '18)
I have a base android project that gets tweaked and would like to generate different APKs. Typically the changes are help links, icons/images, hiding certain functions etc.
In iOS (Xcode) and in Win store app (VS 2012 exp), it is possible to create multiple targets to control the resources bundled with the target as well us programmatically change behavior using the C flags.
Is it possible to do the same for an android project using eclipse ADT? The main issue I see is that, each APK changes the bundle signature (like com.xxx.yyy) and since every file has that package com.xxx.yyy in the files, it is not possible to use that file in a different project (which has a signature like comm.aaa.bbb).
In eclipse .apk builds with Ant and don't support multiple APKs build. Of course you can write your own script, but it will be difficult.
Fortunately, there is another build system, which is called Gradle and it's supported by android developers.
http://tools.android.com/tech-docs/new-build-system/user-guide
You are interested in a section called "Build Variants"
But not everything is so simple, Eclipse with ADT and Gradle are not compatible but Android Studio yes.
The source of this problem is Java itself, where you can't have things similar to #ifdef and most compiler don't allow completely replacing a class or part of it either.
I actually have a base project from which I build 6 APKs already, and more soon.
Each APK uses its own package name, however the whole code is under a single package, but that doesn't create any issue.
There's however many issues:
- All resources, all classes will be in the target APKs, whether used or not.
- Different behavior means different code or different resources, each of which must be handled differently.
For resources, it's "quite easy", just make replacement resources in the final application projects. However unused resources will be left over.
For classes, that's where it becomes very complicated.
To create slightly different behavior you can use reflection and interfaces, each APK implementing it's own version of the interface using a common name eg myActivityPrj which is retrieved using reflection.
Sometimes it's also easier to test the APK package name from within the code, so in the Application object, I set some boolean as to which APK is actually running. Making sure to use those only from the UI to avoid any performance hit.
To create very different behavior, for example an activity is not used in an APK, well, could use above method and a flag saying available or not, but what a waste of space inside the APK!
Another option is to break-down the central project in smaller pieces, if at all possible!
To actually make APK smaller, I found only one way so far: create a Java project which will copy the central project and then remove and/or replace files within this copy, from a remote source tree (a directory named "replacement-files" which contains a res and src folder).
For resources, that java project will actually parse all strings.xml and remove unused strings from a hard-coded list, can't trust lint output as some resources are used in sub-projects and lint doesn't care.
So far, the APK that includes all features is about 10MB, one variation is about 4MB, whereas it should actually be less than 2MB. Another variation is about 8MB, whereas it should really be 2 or 3MB. The above method is overly complicated and being able to removed unused code and resources is getting more and more complicated.
I've looked at various other solutions, but they're all very complicated with a lot of restrictions, constraints.
After 4 years of development on Android, my only conclusion is that Java is the poorest choice possible for a mobile device: slow, inefficient, resource hungry, and very inflexible. Looking at the NDK, it appears very inconvenient and very limited.