If you’ve read my previous post about breaking Android’s 65K limit (and if you hadn’t, what are you waiting for?), you’re already pretty familiar with Android’s 65K limit, why it exists and how to solve it. Which means you’ve been itching to know what the future of multidexing has in store (and what does a tooth-fairy-supporting candy-on-a-stick has to do with it).

As small recap to start with, if you will:

Since its’ inception, Android ran a virtual machine called Dalvik. The Dalvik VM ran a compiled file called dex (Dalvik Executable) which has a tiny limitation – even though the file contains the entire code for the application, its id field was limited to 4 hexadecimal digits. So when an application had over 0xffff methods (=65,536 in decimal), the dex file simply could not be created, meaning applications with so many methods could not be created.

That posed a problem as applications became more and more diverse and complex, and as many developers looked to speed their development process by not doing everything from scratch, but by using more and more third-party libraries (SDKs) that help them achieve their goals faster.

Android released a support library which helps you create an application with over 65K methods. In a nutshell, the compilation process to of Java bytecode to dex was enhanced so that once the limit is reached, a secondary dex file is created. The support library then offered a static method Multidex.install which is called when the app is being launched and tells the class loader to look for methods in places other than the one dex file is expects.

However, we’ve seen the solution is not ideal. Issues ranging from prolonged compilation time to a static process repeating every single time the app is launched made the multidex solution a workaround compromise rather than something Android developers could truly trust. What might be the most burning issue is the lack of ability to predex (compile the not-likely-to-change parts of your app to dex only once; Again, for more information, take a look at part 1).

And Then Came Lollipop: Predex before You Multidex

Recognizing many problems with the Dalvik virtual machine (the methods limit being just one of many), Google revolutionized the Android System with Lollipop (API 21 or higher; Android 5.0 or higher).

The Dalvik virtual machine is deprecated starting with Lollipop. Instead, a new virtual machine has risen to power – ART (Android Runtime). The ART virtual machine operates on an .oat file, which is basically just a dex file without any limit on the method count (well, it’s actually much more than that, but why bore you with the details? You can read more about it in the documentation).

One of the great advantages of ART over Dalvik is that it computes plenty of optimizations during the app install process. That includes an APK with more than one dex file. How? ART simply creates an .oat file from the dex files when the app is installed. If there are several dex files, then it simply combines them to one .oat file and that’s it. Once the app is installed, nothing special needs to happen anymore. Moreover, once the Multidex.install will be called it will quickly exit because the machine already supports multidex. You don’t have the pay the penalty of multidex every single time you launch the app.

And that, ladies and gentlemen, gives us the benefit of having an unlimited methods count but still enjoy the predex option. Because when you compile your app for Lollipop, Gradle will still predex, but it won’t merge them together! Instead, all of these dex files will be entered “as is” into the APK and the ART installation process will combine them to an .oat file. So not only will you still have predex, but remember that lengthy script that prolongs your compilation time? Forget about it. Things really are starting to move in the right direction, aren’t they?

Yes, but… It will only do so if you compile your app against Lollipop or higher! And with Lollipop reaching just slightly more than a tenth of the market (11.6% according to the official Android data), most app developers aren’t likely to be developing solely for Lollipop. However, this seems to be the direction Android is heading. As newer versions of Android become more popular, and as Lollipop itself will shortly be known as an ‘older version’, development of multidex apps with enhanced compilation heuristics will become the more common practice.

Android Lollipop: Predex before you Multidex

And that, ladies and gentlemen, gives us the benefit of having an unlimited methods count but still enjoy the predex option.

What can you do in the meantime to speed up your compilation process during development?

Android Studio (or more specifically Gradle) introduces various compilation variants, such as build type, product flavors and so on. Each one of these variants can have completely separate properties – from SDK version through Proguard all the way to a whole unique and separate resources directory.

You could in fact define a variant for development and set its minSdkVersion to 21 (Lollipop). That way, every time you compile your app, you’ll get the multidex with predex (and even if your app isn’t multidex, you can still save up some seconds by foregoing the merging of dex files during compilation). Your by-products don’t suffer the overhead, but you can still compile for extensive testing and release for wider audiences with little to no trouble.

How does one go about achieving this? Quite simple actually – here’s how you can define a product flavor called “myDev” in Gradle that does just that:

android {
    productFlavors {
        myDev {
            // target Lollipop, don’t run proguard, etc...
            debuggable true
            minSdkVersion 21
        }
        myTesting {
            // create a debuggable version for testing against the real targeted
            // SDK version (targeting roughly 95% of the market)
            debuggable true
            minSdkVersion 15
        myRelease {
            // create a release version targeting roughly 95% of the market:
            minSdkVersion 15
        }
    }
    ...
}

You can pretty much play with these definitions all you’d like and define as many product flavors, build types etc as you want.

There are two main issues with this ‘solution’ which should make you stop and wonder:

The first catch is that you must have a Lollipop device (or higher once higher versions will be made available) to test your app during development. But hey, it’s always a good practice to check your app against newer version of Android when they come out, isn’t that right?

The more important catch you should keep an eye out for is that you should never forget which SDK version you’re still targeting. It’s easy to use fancy new APIs and features while developing without inhibitions, but you should always be careful and make sure they’re supported in all versions you yourself want to support. The relatively minor development speedup will become completely negligible come deployment day and you app suddenly doesn’t work in release or is not backwards-compatible.

Closing Thought

So as you can see, it’s really not that difficult today to build apps that are well over 65K methods. It’s actually quite simple (I believe I’ve used the ‘ridiculously’ adverb). But nothing comes without a price –  As I’ve explained above it may complicate or prolong your compilation and development process, or force you to rethink the way you develop, not to mention might force you to make the transition to Android Studio and/or Gradle which you might not be ready to do just yet. It’s worth noting that while multidexing with other IDEs can be done, it’s considered a lot less simple.

We’ve discussed in the post how easy it is to break the 65K limit, but should you choose to try avoiding this, you’re welcome to read my next post where I’ll delve into some of the roads less travelled to achieve just that.