I’ve been talking a lot about Kotlin in this blog, but now that Google is also talking about Kotlin, and that Kotlin 1.0 RC has been released, there’s no doubt that Kotlin is much more than just an alternative for Android. Kotlin is here to stay, and I recommend you to start learning about it.
Where do I start learning Kotlin for Android?
There is already a lot of information, but if you want to really focus and learn fast, I recommend you these sources:
– Kotlin reference: It’s the best place you can go if you want to dive into all the details regarding the language. One of the nicest references about a language I know.
– This blog: previous link send you to a place where I compile all the articles that talk about Kotlin. You shouldn’t miss it, there are articles for beginners and medium levels.
– Kotlin for Android Developers, The book: The best way if you want to learn fast and learn it forever. If you already know about Android, this will be a fast track to use Kotlin in your projects. I’ve been working on it for a long time and updating it after new releases. It’s up to date with Kotlin 1.0 RC. Besides if you subscribe to the list, you’ll receive 5 first chapters for free and a discount at the end of the free ebook.
Show me the tricks!
I’ve been talking a lot about Kotlin before in this blog, but this is a compilation of things that Kotlin can do for you to simplify Android code. This will be a set of independent examples in no particular order.
Click listeners are clean and fun to write
The lack of lambdas in Java 7 is the reason why listeners and callbacks are so awful to write. Kotlin has beautiful lambdas and a nice compatibility with Java libraries. So it’s able to map interfaces with one method into a lambda. You can just do:
myButton.setOnClickListener { navigateToDetail() }
And that’s all.
Why are layouts so difficult to inflate? Not anymore!
When you are in a adapter for instance, and you need to inflate a layout, this is the code you will have to write:
LayoutInflater.from(parent.getContext()).inflate(R.id.my_layout, parent, false);
Why parent can’t just inflate its own layouts? Well, with Kotlin you can. You can create an extension function that will do it for you:
fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View { return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot) }
ViewGroup
now has a new inflate
function that will receive a layout resource and an optional attachToRoot
. With default values you can create several versions of the same function without the need of overloading the function. You can now do:
parent.inflate(R.layout.my_layout) parent.inflate(R.layout.my_layout, true)
ImageView, load your image!
ImageView
can’t directly load images from network. We have some libraries that create custom views, such as NetworkImageView
, but this forces you to use inheritance, which can lead you to problems at some point. Now that we know we can add functions to any class, why not doing it that way?
fun ImageView.loadUrl(url: String) { Picasso.with(context).load(url).into(this) }
You can use the library you want inside this function. But magic is in the function itself. You now have a super-powered ImageView
:
imageView.loadUrl("http://....")
Nice.
Menu switches are so ugly… Not anymore!
When overriding onOptionsItemSelected
, we’ll usually create a switch
with a good set of branches that always have to return true, but the last one that calls super. If there are drawer options among these actions, its even worse, because you also have to close the drawer. An alternative (just to show you what you can do, not saying it’s the best solution) could be to create extension functions that do those things for you.
First, we can create a consume
function, which means that it’s consuming the event (returning true), and receives a lambda that will do the work we want to do for that branch. The same can be done for the drawer. If it consumes the event, it means that we are closing the drawer after the action is clicked:
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { R.id.action_settings -> consume { navigateToSettings() } R.id.nav_camera -> drawer.consume { navigateToCamera() } R.id.nav_gallery -> drawer.consume { loadGallery() } R.id.nav_slideshow -> drawer.consume { loadSlideshow() } else -> super.onOptionsItemSelected(item) }
How these functions look?
inline fun consume(f: () -> Unit): Boolean { f() return true }
And very similar for the drawer:
inline fun DrawerLayout.consume(f: () -> Unit): Boolean { f() closeDrawers() return true }
The good thing is that these functions are inline
, which means that the function is substituted by the code of the function in compilation time, so it’s as efficient as writing the code directly into the place of the call.
Snacks are like toasts… but uglier
The code to show a snack from the design support library is even uglier than toasts. But we can do it better in Kotlin. We can achieve something like this:
view.snack("This is my snack") view.snack("This snack is short", Snackbar.LENGTH_SHORT)
And what if we have an action? No worries, Kotlin to the rescue:
view.snack("Snack message") { action("Action") { toast("Action clicked") } }
We can create small DSLs for anything that bothers us. What we need?
inline fun View.snack(message: String, length: Int = Snackbar.LENGTH_LONG, f: Snackbar.() -> Unit) { val snack = Snackbar.make(this, message, length) snack.f() snack.show() }
This first function creates the snackbar, makes the snackbar execute the extension function we are providing, and then shows itself.
That function will create the Snackbar action. This is how the action function looks:
fun Snackbar.action(action: String, color: Int? = null, listener: (View) -> Unit) { setAction(action, listener) color?.let { setActionTextColor(color) } }
You can even specify a color for the text of the action. If you don’t, the default value is null, and the last line decides what to do. Don’t you love this last line?
color?.let { setActionTextColor(color) }
The code inside let
will only be executed if color
is not null.
I don’t have the context right now… but who cares?
In Java, when we are for instance finding a view, we have to wait until the layout of the activity is inflated until you can assign a value to a field.
And the same happens to the context. If an object is depending on the context, you need to declare the field at the beginning of the class, and then assign a value during onCreate
.
With Kotlin delegation, you can just delegate the value to the lazy
delegate, and the code won’t be executed until the property is first used:
override val toolbar by lazy { find(R.id.toolbar) } override val dataBase by lazy { DataBase(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail) setSupportActionBar(toolbar) dataBase.loadWhatever() }
The find
function belongs to Anko library. But you can do something similar quite easy:
inline funActivity.find(id: Int): T = findViewById(id) as T
More lambdas, more beautiness
In Java we need to create objets for everything. A good example is postDelayed
, where you need to create a complete Runnable
. Kotlin interoperability just requires a lambda, and it’s much nicer and readable:
view.postDelayed({ doWhatever() }, 200)
And what if you want to create a thread that runs something?
Thread().run { // Running in a thread }
“I hate AsyncTasks!!”. Well, then don’t use them
Thanks to Anko library, we also have a small DSL to deal with background tasks.
doAsync() { // Do something in a secondary thread uiThread { // Back to the main thread } }
It is also context aware, so if it’s called inside an activity, the uiThread
part won’t be called if the activity is finishing.
Why is dealing with collections so difficult? Not anymore
The short answer is the lack of lambdas and functional operations. But Kotlin can work with them, so sorting, transforming, mapping or filtering are just a function call away.
return parsedContacts.filter { it.name != null && it.image != null } .sortedBy { it.name } .map { Contact(it.id, it.name!!, it.image!!) }
You can check a complete list of operations for collections
Operator overloading: let your imagination fly
Who said you can’t access to the views in a ViewGroup
as if it was an array? Wouldn’t it be nice? But it must be difficult… of course not. You just need to create an extension function that acts as an operator.
operator fun ViewGroup.get(pos: Int): View = getChildAt(pos)
You can now do:
val view = viewGroup[2]
You could even create an extension property that returns a list of the views:
val ViewGroup.views: Listget() = (0 until childCount).map { getChildAt(it) }
Now you have a direct access to the views:
val views = viewGroup.views
Fed up with so many getters, setters, toString(), equals()…?
Data classes in Kotlin give all this for you.
data class Person(val name: String, val surname: String, val age: Int)
We’re done here.
Starting activities the easy way
Anko also provides some nice functions to navigate to other activity without the need of creating an intent, adding the extras, calling the function… Everything can be done in a single line:
startActivity("id" to 2, "name" to "Kotlin")
This will create a set of extras for the intent with the values specified by the list of pairs the function is receiving as a parameter.
Android Extensions, or how to forget about findViewById
With Kotlin Android Extension, just by adding a specific import, the plugin will be able to create a set of properties for an activity, a fragment, or even a view, so that you don’t have to worry about declaring or finding those views. The name of the properties will be the ones defined in the XML you are importing. So for instance, in a RecyclerView
adapter, you could do this in the ViewHolder
:
import kotlinx.android.synthetic.main.item_contact.view.* ... fun bindContact(contact: Contact) { itemView.name.text = contact.name itemView.avatar.loadUrl(contact.image) itemView.setOnClickListener { listener(contact) } }
But this can be cleaner. If you’re using the same variable several times, you can use some functions from the standard library, such as apply
:
fun bindContact(contact: Contact) = itemView.apply { name.text = contact.name avatar.loadUrl(contact.image) setOnClickListener { listener(contact) } }
Shut up and take my money!
This is a sneak peek of what Kotlin can do for you. Many of these things are just a syntactic sugar that improves readiness, helps write cleaner code, avoids boilerplate and, the most important thing, makes you feel like a ninja.
Kotlin has many other awesome features you’d love to learn. The language is really fun and creative, it’s pragmatic (just a small set of incredible features) and it’s totally integrated with Android development.
So I recommend you to take a look at the book and get it now.
Really interesting ! Thanks for the tricks 😉
“Google is also talking about Kotlin” – I don’t understand when an employee from Google Talks about something in personal blog, How can we conclude the employer is interested in that context also.
I am totally confused why we need kotlin over java.
It’s not its personal blog, it’s the official channel for Google Developers at Medium. And it obviously doesn’t mean they are supporting it, just that they talk about it as an alternative, which can be understood as a “We are not opposing you to use it”. There’s no “real” need of using Kotlin apart from the fact that is a modern language that provides a lot of development techniques Java 7 doesn’t. Do you need it? No, you don’t, as we don’t need Java 9 or Swift against Objective-c. But the world keeps evolving.
i am really not understanding that is there a need to replace java with kotlin perhaps tomorrow with some other?
isn’t it?
Why would you stick to Java if you can use Kotlin, which allows you to write less code, use a more functional style of programming, and generally has a smarter compiler (compilation time is indeed higher) that will lessen the burden on the programmer?
fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false) {
    LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
}
how to use that?
shouldn’t be:
fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false) : View {
return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
}
Yeah sorry, that’s a mistake. I’ll change it.
Hey Antonio, does the snackbar examples still work with Kotlin 1.0 ? I’m not being able to compile it! Thank you
Hey Fábio! Here it is a gist with the complete set of functions I used. I didn’t use them intensively, so there could be some errors, or some not covered cases: https://gist.github.com/antoniolg/cdd070245b431b226ba3
I’ll review the article, maybe something’s wrong.
Antonio, your first tip here shows a lambda. I had a quick look in the Kotlin documentation but couldn’t find an answer, do Kotlin closures *always* capture a reference to “this”, in the same way that an anonymous inner class would in Java?
Because capturing of “this” is by far my biggest peeve when performing Android development. It means you can’t safely use anonymous inner classes for any long running callbacks (networking etc.) because they capture references to fragments and activities that will be destroyed and recreated during a configuration change (e.g. screen rotation).
Yeah, a lambda generates the same bytecode as an anonymous function (if the function is not inline). So you need to be careful with that the same way you would in Java.
Seems Kotlin will die when Android will finish with Java, and replace it to OpenJDK, or I’m wrong?
The kotlin reference link is not valid:-) You have to update it
True! Fixed, thanks a lot.
what I like is this simple extension:
fun T.log(prefix: String) = apply { if (BuildConfig.DEBUG) Log.d(“TAG”, “$prefix ” + this.toString()) }
I have been working on Kotlin for couple of weeks by converting the Activities of the android app I developed java to Kotlin. Kotlin seems and feels an easier language than java. The best thing about is that I could use Java and kotlin activities side by side. So I didn’t have to convert all my Activities to Kotlin before I could test it. However, my question is I read that Kotlin a cross platform app as in Android and iOS. How does that work?
Please fix broken formatting in the very beginning of the article
Done! Thanks for noticing.
Thank u so much, this features are awesome 🙂