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>
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!" );
}
}
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
.
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
- Butterknife
View "injection" library for Android