Scala on Android

The comprehensive documentation

  • Information reliability Sustainable Won't become outdated
  • Last edit Fri Jul 10 19:44:32 2015 +0200
  • Edit on GitHub

Typed Resources (TR)

As an extension of Android's R class, the Android SDK Plugin for SBT introduces a the TR class. It generates type safe mappings from ids in XML views to their respective class. This is explained best by a simple example.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">

	<TextView
		android:id="@+id/my_title"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />

</LinearLayout>
  • Information reliability Sustainable Won't become outdated
  • Last edit Fri Jul 10 19:44:32 2015 +0200
  • Edit on GitHub

Java

Based on the XML view definition above, you will typically search for the TextView by its id to specify the title at runtime. This is a very common use case, and in Java it works as shown below.

public class MyActivity extends Activity {
    @Override
    protected void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );

        setContentView( R.layout.view );

        TextView title = (TextView) findViewById( R.id.my_title );
        title.setText( "Hello Java!" );
    }
}
  • Information reliability Sustainable Won't become outdated
  • Last edit Fri Jul 10 19:44:32 2015 +0200
  • Edit on GitHub

Scala

It is of course possible to do the exact same thing with Scala.

class MyActivity extends Activity {
    override def onCreate( savedInstanceState: Bundle ) = {
        super.onCreate( savedInstanceState )

        setContentView( R.layout.main )

        val title = findViewById( R.id.my_title ).asInstanceOf[TextView]
        title.setText( "Hello Scala!" )
    }
}

But thanks to the Typed Resources you can get rid off the cast and therefore simplify the code and improve type safety at the same time.

class MyActivity extends Activity with TypedActivity {
    override def onCreate( savedInstanceState: Bundle ) = {
        super.onCreate( savedInstanceState )

        setContentView( R.layout.main )

        val title = findView( TR.my_title )
        title.setText( "Hello Scala!" )
    }
}

The TR mappings are generated on every compile, when the Android SDK Plugin for SBT detects changes in the R class. Your IDE usually helps you to keep the R up to date behind the scenes, but it won't do that for the TR class. You can still achieve a similar effect if you open your project sbt shell and run ~compile. The tilde before the command tells sbt to repeat this task whenever it detects a file change.

TR mappings only work for XML widgets that use the android:id="@+id/xxx" property. If you chose not to use the TR class you may want to disable it for performance reasons in your project's sbt configuration via typedResources := false.

  • Information reliability Sustainable Won't become outdated
  • Last edit Wed Jun 24 17:48:48 2015 +0200
  • Edit on GitHub

Butterknife

The last Scala code example may be simplified further if your use case requires the view reference to be a class field.

class MyActivity extends Activity with TypedActivity {
    lazy val title = findView( TR.my_title )

    override def onCreate( savedInstanceState: Bundle ) = {
        super.onCreate( savedInstanceState )

        setContentView( R.layout.main )

        title.setText( "Hello Scala!" )
    }

    override def onResume() = {
        super.onResume()

        title.setText( "Welcome back, Scala!" )
    }
}

This does however force you to take care when accessing the title field because it will evaluate to null if the setContentView() class has not been executed yet. The workflow is very similar to the famous Butterknife library, but works with basic language features and is much more transparent.

Further reading

Comments