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, nolaunchActivityForResult
- The
launchActivity
method is only available inContext
classes, and the override with theActivityOptions
andrequestCode
only works forActivities
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 on
Context
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
ornewInstance
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