Rewiring Android
with Scala

by Nathan Hamblen

http://code.technically.us/

The Android platform provides a set of well designed, object-oriented APIs.

These interfaces are written in Java, for Java.

So: Why use another language?

Let’s say I want to run some code.

code

Like in this DialogInterface.OnShowListener:

Interface used to allow the creator of a dialog to run some code when the dialog is shown.

Here we go!

dialog.setOnShowListener(
  new DialogInterface.OnShowListener() {
    public void onShow(DialogInterface interface) {
      runSomeCode();
    }
  }
);

I also need to run some code in a background thread:

new AsyncTask<MyObject, Integer, Integer> () {
  protected Integer doInBackground(MyObject... objs) {
    runSomeCode(objs[0]);
  }
}.execute(myObject);

And post code back to the UI thread:

handler.post(new Runnable() {
  public void run() {
    runSomeUICode();
  }
});

Oh, geez. Can’t I just—

RUN SOME CODE?

dialog.setOnShowListener { di: DialogInterface => 
  runSomeCode() 
}

future { runSomeCode(myObject) }

post { runSomeUICode() }

Not in Java. :(

Java’s evil twin

Scala can stand in for Java in almost any situation.

Including Android programming.

Before you sneak code into a virtual machine, you can do whatever you want.

You want closures, mix-ins, even generic type reification?

Scala’s compiler is an eager conspirator.

But once the runtime show starts, Scala won’t pull anything fancy.

Live compilation, or open classes?

That would be a dead giveaway.

Those tricks may blur away on desktop hardware.

But on a mobile device, such artifice revealed in slow motion.

Scala’s advanced techniques compile to JVM primitives that are executed normally.

So that neither the JVM, nor Android’s Dalvik VM

—or more importantly their users—

know the difference.

Scala blends in to Android like a Russian spy at Microsoft.

spy

Scala niceties

Traits let you mix behavior into base Android classes.

trait ScalaActivity extends Activity {

Like a direct path to the UI thread:

lazy val handler = new Handler
def post(block: => Unit) { 
  handler.post(new Runnable{
    def run { block }
  })
}

To take care of business in one line.

post { dlg.dismiss() }

Implicit conversions extend APIs statically.

implicit def f2cancel(block: DialogInterface => Unit) = 
  new DialogInterface.OnCancelListener {
    def onCancel(dialog: DialogInterface) { 
      block(dialog) 
    }
  }

So your code doesn’t have to.

new AlertDialog.Builder(this)
  .setOnCancelListener { 
    di: DialogInterface => finish() 
  }

We can even add “automatic resource block management.”

def editor(
  block: SharedPreferences.Editor => Unit
) = {
  val editor = sp.edit()
  block(editor)
  editor.commit()
}

And commit behind the scenes.

sp.editor { e =>
  e.putString("oauth_token", token.value)
  e.putString("oauth_token_secret", token.secret)
}

Plus, you can use your favorite Scala libraries!

future { 
  http(some_url >> { stm =>
    val bitmap = BitmapFactory.decodeStream(stm)
    post { some_image.setImageBitmap(bitmap) }
  } )
}

So what’s the catch?

Bad casting

Scala isn’t just statically typed like Java.

It’s statically typed better than Java.

And because Scala’s type system is more powerful than Java’s,

expectations for type safety in application code are higher.

Scala makes us picky.

Things start off all right.

<Button id="@+id/my_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/my_button_text"/>

But then—ew.

Button myButton = 
  (Button) findViewById(R.id.my_button);

And then—no.

val myButton = 
  findViewById(R.id.my_button).asInstanceOf[Button]

Why does it return just a View?

We declared the subtype in the layout.

But aapt dumbed it down to this:

public final class R {
  ...
  public static final class id {
    public static final int my_button=0x7f060003;

By the time our code is compiled, the crucial type information has been discarded.

It can’t be restored by any coding trickery.

If only there were some way to add our own step to the build process.

sbt-android-plugin

This sbt plugin works with Android SDK tools to build applications in a controlled, predictable, and flexible process.

And you can hack it.

You can add a pre-compilation step to generate a file TR.scala that is like R.java, but with types.

Lookup this blog post if you want to know how it works ↓

coderspiel

To just use it, you need to have Simple Build Tool installed.

Then you declare the plugin dependency in your sbt project, and mix a TypedResources trait into the project definition.

Perhaps an example would help?

Meetabout

icon

Meetabout turns web sites into meetups.

(Or, it will when it’s finished.)

Let’s clone it from github:

$ git clone git://github.com/meetup/meetabout.git

And start sbt:

$ sbt

It’s downloading the plugin! Why?

Because in project/plugins/Plugins.scala, we have this:

import sbt._

class Plugins(info: ProjectInfo) 
    extends PluginDefinition(info)
{
  val android = "org.scala-tools.sbt" % 
      "sbt-android-plugin" % "0.5.0"
}

Now we’re in the sbt console. We need to update the application’s dependencies first:

> update

And then compile:

> compile

Uh oh!

You need to set ANDROID_SDK_HOME or ANDROID_SDK_ROOT

> ^D

$ export ANDROID_SDK_HOME=/usr/local/android-sdk/

$ sbt

Now it will work.

This project has been enhanced with our obsessive-compulsive-typing trait:

class MeetaboutProject(info: ProjectInfo) 
  extends AndroidProject(info: ProjectInfo) 
  with MarketPublish with TypedResources {

So it generates an extra source before compilation, TR.scala.

Now in app code, we can do this cool stuff:

class SomeActivity extends Activity with TypedActivity {
  val name = findView(TR.namefield).getText

Build and put into the emulator:

> install-emulator

Load up a sweet web site.

scala-lang

Share it with some installed apps.

share

Somebody’s meeting up about this page!

share

Meetabout queried the Meetup Everywhere API to find content tagged with that URL.

Now we just need to find or create one one near us, sign up for it, etc...

It’s going to take a little while to build all this into the app.

scala-meetups

But this is the general idea!

scala-meetups

Forks welcome.

In conclusion

Scala’s structural similarities to Java allow it to work as normal on Android.

Scala language constructs can be implicitly added to Java APIs that don’t know anything about them.

Simple Build Tool can build whatever crazy idea you come up with.

So get to work.

workers