You won’t believe this one weird trick to handle Android Intent extras with Kotlin
Eugenio Marletti
1764

Starting Activities with Kotlin — My Journey

This is a reaction to the article You won’t believe this one weird trick to handle Android Intent extras with Kotlin by Eugenio Marletti. It reminded me at my first attempts to make the startActivity API better by using the Kotlin feature Optionals and Extensions. This article describes different solutions to start Activities because we don’t have static methods in Kotlin to build our loved newInstance() or newIntent() methods.

Regarding Eugenio Marlettis article and his library, I must admit, I never heard of the concept of putting static getters/setters on the Activity class to manipulate an Intent. It also doesn’t sound useful to me. I’ll most likely never use it but I’m very happy to see Kotlin libraries specifically targeting the Android community.

newIntent() in Java

ThenewIntent method for Activities is an alteration of thenewInstance method for Fragments which is even part of the official Fragment documentation.newIntent isn’t official but a logical step for Activities which is widely used.

This is how it looks in pure Java:

The Intent is build inside the UserDetailActivity and not outside. You cannot make it wrong and accidentally forget an extra. Also notice that the constant for the key is private.

Now let’s translate this to Kotlin! When you’re new to Kotlin you’re maybe interested in a 1:1 translation which I’ll improve later on.

Because kotlin has no static fields a companion object is used, a single shared object between all instances of the hosting class.

Generic launchActivity() extension function

Because tried to be a “clever guy”, new to Kotlin and in love with all the new possibilities I tried to use them all at once and created cool extension functions to launch Activities. You can’t find them here when you’re interested. The implementation isn’t that interesting, I’ll just show you how it works:

Isn’t it cool? Here are some noticeable facts:

  • less code, full flexibility than starting Activities the normal way
  • one method (launchActivty) used for everything, no launchActivityForResult
  • The launchActivity method is only available in Context classes, and the override with the ActivityOptions and requestCode only works for Activities

What I don’t like:

  • Intent construction not within the Activity file and the extra name const is public
  • not “type safe” like the newIntent method from Java

It’s nothing more than a better startActivity()

Moving the launch function to the Activity file

Then I started to get crazy and created overrides of this launchActivity method for every Activity to move the Intent construction to the correct file.

Nailed it! Everything is scoped as in Java, it’s not possible to forget an argument, as in Java. 🎉

Actually not…

I lost functionality compared to simply calling the extension function launchActivity(). I didn’t create an override for both extension functions, the Activity and the Context extension. So I can’t call launchUserDetailActivity() with a requestCode. And because the Activity will be launched directly I cannot use the generated Intent to use startActivityForResult(Intent).

And it’s a lot code, I don’t want to write all this for all Activities. I also had copy past errors and after all I cannot recommend doing it this way. But it’s a nice demonstration that it can be better to go one step back.

My current best practice

I stopped using the launchActivity method. I went back to use startActivity and the already existing overrides. This also makes it easier for new people to Kotlin. They can search the code for “startActivity” and find the correct spot where the Activities are connected. This is a big win.

My Intent builder function is still an extension function for Context. I still pleased with the decision. It only might get messy when you have dozens of those methods.

Changes:

  • I moved the extra key constant INTENT_USER_ID out of the Activity. In all languages you define constants outside of a class. It’s different in Java, because it’s not possible to define anything outside of a class.
  • The UserDetailIntent(User) method is now an extension method. This restricts the visibility of this method to classes and objects where you can actually use this method. When you have a bad feeling about the uppercase method name, read this and feel free to change it.
  • apply() practically speaking replaces builders in Kotlin. It returns the target object after it’s configured within the lambda.

The good parts:

  • Intent creation and parsing is all within the Activity file
  • the Intent construction method doesn’t require setting the Context explicitly
  • it can only be called in or onContext classes
  • you can define optional parameters i.e. inEditMode: Boolean? = false
  • no companion object is used which requires some boilerplate code to mimic “static” methods we know from Java.

The bad parts:

  • no universal name such as newIntent or newInstance

What you do think about my methods to start Activities? I excited to get your feedback or tips to improve those methods even further. Hit me on Twitter for suggestions