Learning Kotlin: Some Anko Examples

Kotlin

Something I've been doing recently is learning how to program in Kotlin. Kotlin is a JVM-compatible (that's Java Virtual Machine) language with functional features, much like Scala, except it's a bit younger and easier to set up in an Android environment. A couple of my current takeaways:

  • You'll find people comparing Kotlin to Scala a great deal

  • Learning Kotlin (or Scala for that matter) makes you realize how much smarter you can work without having to lean on your IDE to generate massive amounts of boilerplate for you.

  • JetBrains is really doing a great job as the de facto corporate sponsor of the language. JetBrains is responsible for some of my favorite IDEs: Webstorm, IntelliJ, and Android Studio (which is more or less a special build of Intellij).

I do most of my Java-esque development on IntelliJ, but if you want to run any examples you see here, try the Command Line Interface:

$ curl -s get.sdkman.io | bash
$ sdk install kotlin

Then, to compile and run your Kotlin programs stand-alone:

$ kotlinc filename.kt -d filename.jar -include-runtime
$ java -jar filename.jar

One of my favorite features is the ability to define inline functions:

// inlines.kt

inline fun doSomething(f : () -> Any) : Unit {  
  println("Doing something with the function")
  f()
  println("Done!");
}

fun main(args : Array<String>) : Unit {  
  doSomething {
    println("I'm in the function now!")
  }
  // OUTPUT: 
  // Doing something with the function
  // I'm in the function now!
  // Done!
}

Anko

Anko is another JetBrains project in pure Kotlin that aims to simplify certain aspects of the Android API. The major feature (which I suspect will be pulled into its own package) is the view generation DSL.

Some background: to create a view in Android, the recommended approach is creating a layout XML resource. Here's an example:

<?xml version="1.0" encoding="utf-8"?>  
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.example.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_menu_edit" />

</android.support.design.widget.CoordinatorLayout>  

This is the basic template for a blank activity with a floating circle in the bottom right. I'll say that again, it's about 34 lines of code defining a blank activity with a button in the bottom right.

The Anko DSL for generating views is much, much more concise. Here's pretty much the same view in Kotlin/Anko:

coordinatorLayout {  
  verticalLayout {
    // maybe put some content here
  }
  floatingActionButton {
    imageResource = android.R.drawable.ic_menu_edit
    onClick {
      ui.owner.startActivityForResult<AddSomethingActivity>(1)
    }
  }.lparams {
    gravity = Gravity.BOTTOM or Gravity.END
  }
}

For those who aren't familiar with Kotlin, those constructs such as coordinatorLayout { ... } and onClick { ... } are function calls: they're inline functions. Essentially, Anko has defined a function called inline fun coordinatorLayout(inner) where inner is a function. Kotlin knows that when an inline function is called with a bracketed block afterwards, that you are defining the anonymous function that will be defined as inner.

It's kind of convoluted to explain, but the outcome makes a great deal of sense; it's organized in the same way that the XML layout is organized, accepts the same modifiers, but is much more concise.

Moreover, I'm able to really define my onClick action inline with the view definition. Sometimes that's not necessarily a good thing, but you always have the option to delegate to another function.

That brings up another interesting thing: I'm calling a function that's usually a member of an Activity subclass under a property owner of ui. This is a suggested view-model type of separation where your SomethingActivity and SomethingActivityUI are separate classes: SomethingActivity is an Activity where the UI subclasses what's called the AnkoComponent<? extends Activity> class: in this case, it's AnkoComponent<SomethingActivity>.

class MainActivityUI : AnkoComponent<MainActivity> {

    override fun createView(ui : AnkoContext<MainActivity>) = with(ui) {
       // coordinatorLayout { ... }
    }
}

And in the MainActivity definition:

override fun onCreate(savedInstanceState : Bundle?) {  
    super.onCreate(savedInstanceState)
    ui = MainActivityUI();
    ui!!.setContentView(this) // `this` is the Activity
  }

Note the ? ("nullable") modifier and !! ("unsafe") operator. Kotlin is designed to be "null-safe"- that is, you can only produce a NullPointerException if you explicitly use the !! operator. The side effect of that is that if you have any sort of state in your class that you want to store without necessarily instantiating that variable with the class in the constructor, you're pretty much going to be chaining "unsafe" and "maybe-null" code.

Note: "maybe-null" is !., as in maybeNull!.someMember- if maybeNull is null. Kotlin will automatically return null instead of forcing the developer to check every step of the way of a long chain of references to see if a member is null before trying to dereference the pointer.

Join me next time as I give a brief primer on Anko's Sqlite features, connecting a listView to a Sqlite table in the Kotlin way.

How to Cite Republished Information

Do not use this information as legal advice.
If you need advice, call or email a licensed attorney.
No attorney-client relationship is created by your use of this site, including any communication with the author in comments.