Kotlin as a first class language!

 
android_kotlin.png
 

This morning my wildest dreams came true - Kotlin became a first class language for Android development! This is exciting and it firms up what I've believed since the summer of 2015. Kotlin is the best language available to write native Android apps.

It's exciting because it means Google listens.

Pressure from developers has made it clear that Kotlin is where we see the platform going. It solves so many problems common to Android app development and brings features many developers lost hope of having. Method references, null data types, flexible control flows, lambdas, extension functions. There are plenty of libraries, hacks, and work arounds, but Kotlin brings consistency. The choice to support Kotlin means it will only get better and continue to flourish.

It's exciting because Kotlin can make you faster.

After the 1-2 days ramping up you find yourself accomplishing simple tasks in a fraction of the time it would have taken in Java. Language level features reduce ambiguity, drive readability, and make code more concise. You have first class nullability and you are forced to deal with it before you ship your app. It's as if JetBrains felt the pain of developing applications in Java and wrote a language to make it better (spoiler, they did.) You can see this throughout the language as you learn to write idiomatic Kotlin. You spend less time writing boilerplate (data classes anyone?) and more time writing interesting code.

It's exciting because it's rock solid on day one.

Years of testing and iteration before Google gave the green light has lead to a language and tool set that just works. It runs in your favorite IDE. It's works on every version of Android. Let me phrase this in another way - When was the last time you got an Android developer tool that just plain works. On day one. Like right now, go get it, and ship an app on the same day it was announced - 

This is the very first time and I hope this trend continues. Google doesn't need to invent everything and this proves that. They can be an amazing facilitator and still win. 

Clearly I am super jazzed about this and it's should be exciting for anyone who writes Android apps. You can check out my other Kotlin posts here and be sure to keep an eye out for more.

Kotlin Bricks: Using Android Extensions instead of ButterKnife

Kotlin Android Extensions is an add-on package and plugin that make it effortless to find a specific View in your layout. Similar to ButterKnife you don't have to write findViewById all over the place. That really where the similarities end and where Android Extensions really make your code (and work life) better.

To get started you need to add these to your module's ("app" in many cases) build.gradle file.

apply plugin: 'kotlin-android-extensions'

Now in your Activity, Fragment, or View subclass you can start accessing the strongly typed views in just two lines.

// add an import
import kotlinx.android.synthetic.main.YOUR_XML_LAYOUT_NAME.view.*

// access the view
tv.text = "Hello World!"

Thats it! There is no injecting, binding, or resetting anything. There is no casting. It's strongly typed so if it compiles, you won't get some runtime exception complaining about casting or a null pointer from a missing view.

Kotlin Bricks: One strategy to avoid nullable types

If you use Fragments, imagine this common situation where you passed values in via the appropriate setArguments call. The arguments bundle contains a model that you'll reference all over the fragment code. Grabbing it from the bundle every time could be messy and wasteful, especially if it never null.

var model:Bundle? = null
override fun onCreate(si: Bundle?) {
    super.onCreate(si)
    model = arguments.getParcelable("model")
    model?.getString("foo")
}

That might be your first approach, however every time you access model you'll need to dereference it with ? or !!. Since I guaranteed at the top that our app will always pass "model" in the Fragment arguments, we can do something slightly differently to avoid all of that.

val model by lazy { arguments.getParcelable<Bundle>("model") }
override fun onCreate(si: Bundle?) {
    super.onCreate(si)
    model.getString("foo")
}

By using lazy delegates we can make the model property non-null and use the Fragment arguments. This technique is useful in Android subclasses where you don't have much control over the lifecycle, but still want control over the nullability of your properties.

lazy works by waiting until the first time you access a property to actually assign it. This usually works well but you have to be cautious when you first call it. For example, calling the in constructor would cause a NullPointerException because arguments was not set yet.

Kotlin Bricks: Avoid lots of safe dereference using apply

Coming from a Java background its very common to null check quite a bit to avoid the billon dollar mistake. Kotlin solves this by introducing a null variant to every type so when you get the dreaded NullPointerException its probably a serious issue you should deal with. When starting out with Kotlin your instinct says drop ? everywhere, you know, just to be safe.

Consider this example where we did a good job to guard against a crash should onNetworkSuccess return after our UI has been destroyed. While simple, there are still three textView? and you could imagine it growing pretty quickly as you make a more complex UI.

var textView: TextView? = null

override fun onCreate(si: Bundle?) {
    super.onCreate(si)
    textView = findViewById(R.id.tv) as TextView?
}

fun onNetworkSuccess(message: String) {
    if (message.isNotEmpty()) {
        textView?.text = message
        textView?.visibility = VISIBLE
    } else {
        textView?.visibility = GONE
    }
}

As an alternative we can use the apply function to not only use the safe operator once but also avoid any unnecessary work if the view ends up being null. I think the code also read better this way.

fun onNetworkSuccess(message: String) {
    textView?.apply {
        if (message.isNotEmpty()) {
            text = message
            visibility = VISIBLE
        } else {
            visibility = GONE
        }       
    }
}

Android Studio vs. IntelliJ IDEA

Many Android new comers haven't experience the pain of Eclipse for Android development. When I started in 2009 it was the IDE and tool kit to use. IDEA from Jetbrains was around and had basic support for Android projects but it wasn't super compelling. In 2010 I made the switch and its been wonderful ever since. However it wasn't until Google I/O 2013 when they released the first version of Android Studio and even then it was a very subtle "we are probably going this direction but still love Eclipse" kind of move.

So beyond the mini history lesson, why does this matter? Because you can still use IntelliJ IDEA Community or Ultimate editions to build your Android apps and there are a couple of good reasons why I do this.

I find it more stable and up to date

Its true Android Studio is built using the open source Community edition, however, its often out of date. It took 6 months for Android Studio to upgrade from IDEA 15 to IDEA 16, which had some fantastic improvements

It does a lot more than just Android

If you find yourself working in multiple languages and frameworks IDEA Ultimate covers you more than Android Studio. I also find it way easier to create simple Java projects using IDEA, which is useful for sketching ideas or building pure Java or Kotlin libraries. If you are building a hybrid app, the web technology support is superior out of the box.

It can be configured without all the bloat

In my workflow I don't use many (if any) Google plugins. In Android Studio I choose to disable 10+ of them removing UI clutter and overhead. On the flip side, IDEA asks you up front what you do day to day to help customize your environment right from the start.

Worst case, its a great back up

If something just isn't right with your Android Studio, try IDEA. It could help sanity check if the issue is truly with your app, computer, or just Android Studio itself.

While IDEA Ultimate is my daily driver, I do still have Android Studio around. Many of the new utilities haven't made it into IDEA and in the off chance I need them its just a double click away.

What is Gradle?

While some of you may know Gradle (or Maven or Ant) from other projects, for Android developers its of great importance to understand and utilize Gradle to its fullest. Gradle ensures your builds run as consistently as possible across multiple devices while empowering you to dynamically change and easily update the core requirements of your application.

Its like a recipe

Take a standard recipe, like this awesome chocolate cake – it contains a description of all the parts and instructions required to make it. For starters, you need flour, sugar, oil, and a bunch of other things. These are the Gradle dependencies. You also need a bunch of tools like a bowl, mixer, and measuring instruments. These are the Gradle plugins. Where do you get all this stuff? Probably your pantry or the grocery store; these are Gradle (Maven) repositories.

Now that you've collected all of your tools and ingredients, you'll need to follow the instructions to actually make the cake. For Android developers this means configuring the android object, telling it how you want the app built. configurationsbuildscript, and many others also provide instructions.

Finally, you've completed the instructions for sifting, whisking, and folding. Now its time to bake this cake! In our analogy gradle or gradlew executable is the oven. You pass in your build.gradle file and it bakes you an APK.

While many stop here, often recipes leave room for interpretation to make it your own. This is where Gradle really shines. You can inject your own ingredients (dependencies), tools (plugins), and instructions (additional code.) Just like modifying a cake, this could change the entire process. Maybe it takes longer to bake (slower build times) or it outputs multiple cakes (like a magical cake copy machine.)

This is just the beginning

After you build a project or two you'll find that many open source projects and tools utilize Gradle. It could be generating more code, archiving artifacts, counting the methods in your app, running adb commands, or even sending a message to your group chat when its done.

Android Bricks: Image loading

There are three major image loading libraries on Android. Their purpose is to manage network requests, caching, and display of images loaded from your web server. This is a key component in many apps and I'll walk your through how to pick one.

Picasso & Glide

I lumped these first two together because they function very similarly internally. Based entirely in the standard Android heap, these represent a straight forward and simple solution to image loading. You access a singleton, with a url and target, then the library does the rest. Its a short and sweet single line with no other required set up.

Picasso

Picasso.with(ctx).load("https://placekitten.com/g/720/480").into(iv)

Glide

Glide.with(ctx).load("https://placekitten.com/g/720/480").into(iv)

As you can see they are nearly identical. The difference is that Glide is configured for better memory performance right out of the box. It decodes images as Bitmap.Config.RGB_565 and resizes them to fit the view they'll occupy. Together these two configurations lead to fewer memory spikes and lower sustained memory usage.

Its worth noting that Picasso can be configured to work near identically, but its not the default. At the time of this writing Picasso 2.5.2 is 18 months old and contains some unfixed edge case bugs you'll need to manually patch. Glide remains in active development and maintains more regular releases.

Fresco

Fresco is a product of Facebook's engineering team and backed by ashmem, making it a significantly different approach to nearly all other open source solutions. It is in heavy development but used on a massive scale. It also displays animated GIFs and progressive JPEGs giving it a leg up if you need support for either.

The biggest down side is the implementation. If you are dealing with a legacy codebase that loads a ton of images or has specialized needs you'll be hard pressed to adopt Fresco in a week, let alone a day. Since its such a different pattern and has its own special rules, you'll want to be 100% sure you like it before making a call one way or the other.

// In your custom Application.java
Fresco.initialize(ctx)

// Load image
draweeView.setImageURI(Uri.parse("https://placekitten.com/g/720/480"))

As you might have noticed, draweeView looks a little odd and it requires an initialization call. With Fresco you cannot use a standard ImageView due to its optimizations around memory usage. One last down side here is that if you have a custom ImageView that applies an effect, Fresco could make it way more complicated and you'll be stuck trying to make it work rather than using something off the self.

Recommendation

  1. If you load a low to moderate amount of images Glide is a great choice with complexity built in if you need it down the road. 
  2. If you need GIFs, progressive JPEGs, really care about memory, or push a ton of images through your app go, with Fresco
  3. If you are totally into Square engineering (and who isn't?) go with Picasso.

Faster Android builds

The bigger your app and team get, the slower your build will inevitably become. Here are a few tips to get you building faster. This guide is geared towards anyone responsible for buying machines for Android developers and focuses on rapid iteration.

Raw power

This is your profession, invest in decent tools. While its true that some famous musicians still play cheap guitars, this really doesn't translate to technology. Aim for these specs.

  1. In a desktop, shoot for as many processing cores as you can afford. 6-8 hyper threaded cores beats 4 cores at a higher clock speed. This means an i7 or Xeon desktop like the Dell Precision 7000 or the MacPro.
  2. In a laptop, portability is nice, but often leads to low power processors. i7 is required and avoid anything ending in U, like the i7-5557U found in 13" Macbook Pro. The Dell XPS i7 15" or the 15" Macbook Pro will keep you building fast on the go.
  3. 16Gb RAM minimum. Everything Android related is a memory hog and gets faster the more memory you can give it.
  4. SSD is required. The faster you get files from one place to another, the faster you build and deploy.

Project

Setting up your project correctly can really make a difference.

  1. Break your app into modules. This means properly decoupling chunks of your app into several standalone pieces. These can be built in parallel and even cached. Should your work be isolated to a single module, this will certainly speed things up.
  2. Carefully consider Gradle plugins and annotation processors. These could be slowing down builds because they are figuring stuff out when you build. Obvious but often overlooked.
  3. Configure your build.gradle to exclude things you don't need during rapid development. This cut off between 10%-30% build time in my experience.
  4. Avoid MultiDex if possible.

Gradle configuration

Gradle can be a blessing or a curse and you need to configure it to work optimally. After applying these settings my medium sized project build times went from 37s to 20s (clean assembleDebug)!

To get started, locate your gradle.properties file:

  • Linux: /home/<username>/.gradle/
  • Mac: /Users/<username>/.gradle/
  • Windows: C:\Users\<username>\.gradle

Next add the following lines to gradle.properties:

org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx3072m
org.gradle.parallel=true
kotlin.incremental=true

Lastly edit your build.gradle. Below is a starting point and according to the docs, there is a formula to adhere to. From experience you need to try out different settings to ensure you aren't negatively impacting your build times.

android {
  dexOptions {
    maxProcessCount 4
    javaMaxHeapSize "2g"
  }
}

Android's 64K Reference Limit

While many downplay the impact of breaking the 65,536 method reference barrier, I've come to give it a second look. "Just focus on shipping" is a saying all to rampant in tech. You often end up with throwaway solutions that really aren't focused on sustainability. There are few reasons I don't believe in Multidex even though I have to deal with it day to day.

  1. It slows down your build process. Not only is it using ProGuard every time you build, you have to bundle up that much more code. You can target API 21+ to bypass the ProGuard part, but you might need to target API 23+ pulling you further away from many of your users.
  2. It could slow down app start up. From personal experience and reported by others, your app could start between 15%-20% slower.
  3. It might be pointing to a larger problem.

At a bare minimum, you need to measure and track your method reference count. The good news is for most apps this is completely avoidable with a few key principals.  

  1. Don't pull in an entire library for a few classes and don't wait for ProGuard to strip out unused stuff for you. Consider grabbing the source directly or using Jar Jar to repackage the dependency.
  2. Avoid as much of Google Play Services, Support Library, and AppCompat as you can. While they provide a ton of handy stuff, you most likely won't use it all. Following Material guidelines is easy, enabling you to quickly build most components in fraction of the method count. With v25 you may be able to take bits and pieces of these libraries, but many still depend on each other.
  3. Be cautious of or avoid auto generated code. If you can't, find or make a better generator. Thrift is a great example where it includes a ton of extra methods many won't use. Also get your definitions in check to make sure Android only gets the enums it needs and not all the junk your server uses too.
  4. All too often people's first step is to search Android Arsenal or Github for a canned solution – write more of your own solutions! They'll be tailored to your app and often slimmer than a general purpose counterpart.
  5. Use ProGuard to remove unused methods. You are probably already doing this, but you may be able to tighten up the rules.
  6. Understand what happens when you (don't) access a private field from an inner class. There could be 1,000s of hidden methods you didn't write!
  7. Lastly, don't wait until you hit 64k methods. Continually check this and other key metrics like bundle size. This is even more important the larger your team gets.

Which densities?

There are seven different DPI qualifiers recognized by Android. Just because they're there doesn't mean you should support them all. By shipping fewer sets of resources you keep your designer sane and your APK a bit leaner. My recommendation is to pick just two or three and let the system automatically scale them for you.

If resources are not available in the correct density, the system loads the default resources and scales them up or down as needed to match the current screen’s density.
— http://bit.ly/DensityConsiderations

So which do you pick? In order of importance - HDPI, XHDPI, and XXHDPI. Collectively these cover 83% of devices. The other 17% may experience inexact pixel placement once scaled and there is some cost (both memory and CPU) to the automatic scaling. In the vast majority of cases this is negligible and you ultimately should optimize for the majority. Serving emerging markets might mean focusing on MDPI and HDPI.

TIP: Have full screen tutorial images? If they absolutely must be bundled, just ship XHDPI version to save on size while maintaining decent quality. Also consider changing the design to something that uses the real app UI. If that's not an option dynamically downloading the right version would be a nice middle ground.