Saturday, December 15, 2012

Scala And Android Were Made For Each Other, Part 2

This is the second in a 2 part post.  To read the first post, Click Here.

Now that we've gone over the Service in our application, lets review the Activity.  Just in case you haven't read part 1, here's a 10 second recap:

We're building a countdown timer for the specific case of tracking a Pomodoro, a 25 minute block of time.  For more info, visit the Pomodoro Technique site, or maybe, order Pomodoro Technique Illustrated...

We've reviewed the Service and seen how the Scala language allows us to reduce a lot of boilerplate code.  Now lets look at the Activity:

1:  class ScalaDoro extends FragmentActivity with Actionable with MessageReceiver {  
2:   /** Messenger for communicating with service. */  
3:   var mService: Messenger = null  
4:   /** Flag indicating whether we have called bind on the service. */  
5:   var mIsBound: Boolean = false  
6:   var running = false  
7:   override def onCreate(savedInstanceState: Bundle) {  
8:    super.onCreate(savedInstanceState)  
9:    setContentView(R.layout.activity_main)  
10:    spawn {  
11:     startService(new Intent(ScalaDoro.this, classOf[BackgroundTimer]))  
12:    }  
13:    if (savedInstanceState != null) {  
14:     running = savedInstanceState.getBoolean("running", false)  
15:     val timerString = savedInstanceState.getString("timerText")  
16:     getSupportFragmentManager().findFragmentById(R.id.timer).asInstanceOf[CountdownTimerFragment].updateTime(if (timerString != null) timerString else "")  
17:    }  
18:    val button = findViewById(R.id.foo_button).asInstanceOf[Button]  
19:    //awesome lack of boilerplate code...  
20:    if (!running) {  
21:     button.setOnClickListener(toOnClickListener(startClickListener))  
22:     button.setText(R.string.start)  
23:    } else {  
24:     button.setOnClickListener(toOnClickListener(stopClickLister))  
25:     button.setText(R.string.stop)  
26:    }  
27:    val donate = findViewById(R.id.donate).asInstanceOf[TextView]  
28:    if(donate != null) {  
29:     donate.setText(Html.fromHtml("<a href='https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2RYS72VS6BJAA'>Is this useful to you? Donate via PayPal.</a>"));  
30:     donate.setMovementMethod(LinkMovementMethod.getInstance());  
31:    }  
32:   }  
33:   override def onSaveInstanceState(bundle: Bundle) = {  
34:    bundle.putBoolean("running", running)  
35:    bundle.putString("timerText", getSupportFragmentManager().findFragmentById(R.id.timer).asInstanceOf[CountdownTimerFragment].getTime.toString())  
36:   }  
37:   def onMessage(m: Message) = {  
38:    Log.i("BAA", "Message in Activity")  
39:    m.what match {  
40:     case BackgroundTimer.TICK =>  
41:      val textFragment = getSupportFragmentManager().findFragmentById(R.id.timer).asInstanceOf[CountdownTimerFragment]  
42:      if (textFragment != null) {  
43:       runOnUiThread {  
44:        textFragment.updateTime(m.obj.asInstanceOf[String])  
45:       }  
46:      }  
47:     case BackgroundTimer.STOPPED =>  
48:      val button = findViewById(R.id.foo_button).asInstanceOf[Button]  
49:      button.setOnClickListener(toOnClickListener(startClickListener))  
50:      button.setText(R.string.start)  
51:    }  
52:   }  
53:   def stopClickLister(v: View): Unit = {  
54:    val button = findViewById(R.id.foo_button).asInstanceOf[Button]  
55:    try {  
56:     running = false  
57:     // Give it some value as an example.  
58:     Log.i("BAA", "Sent message")  
59:     button.setOnClickListener(toOnClickListener(startClickListener))  
60:     val msg = Message.obtain(null, BackgroundTimer.STOP)  
61:     msg.replyTo = mMessenger  
62:     mService.send(msg);  
63:    } catch {  
64:     case ex: Exception => Log.i("BAA", ex.getMessage())  
65:    }  
66:    button.setText(R.string.start)  
67:   }  
68:   def startClickListener(v: View): Unit = {  
69:    val button = findViewById(R.id.foo_button).asInstanceOf[Button]  
70:    try {  
71:     // Give it some value as an example.  
72:     button.setOnClickListener(toOnClickListener(stopClickLister))  
73:     running = true  
74:     val msg = Message.obtain(null,  
75:      BackgroundTimer.START)  
76:     msg.replyTo = mMessenger  
77:     mService.send(msg);  
78:     Log.i("BAA", "Sent message")  
79:    } catch {  
80:     case ex: Exception => Log.i("BAA", ex.getMessage())  
81:    }  
82:    button.setText(R.string.stop)  
83:   }  
84:   //binding code..  
85:   val mConnection = new ServiceConnection() {  
86:    override def onServiceConnected(className: ComponentName, service: IBinder) = {  
87:     Log.i("BAA", "OnServiceConnected called")  
88:     // This is called when the connection with the service has been  
89:     // established, giving us the service object we can use to  
90:     // interact with the service. We are communicating with our  
91:     // service through an IDL interface, so get a client-side  
92:     // representation of that from the raw service object.  
93:     mService = new Messenger(service)  
94:     // We want to monitor the service for as long as we are  
95:     // connected to it.  
96:     try {  
97:      // Register to receive the notifications  
98:      val msg = Message.obtain(null,  
99:       BackgroundTimer.REGISTER)  
100:      msg.replyTo = mMessenger  
101:      mService.send(msg)  
102:      //Now get status  
103:      val status = Message.obtain(null, BackgroundTimer.STATUS)  
104:      status.replyTo = mMessenger  
105:      mService.send(status);  
106:      Log.i("BAA", "Sent message")  
107:     } catch {  
108:      case ex: Exception => Log.i("BAA", ex.getMessage())  
109:     }  
110:     mIsBound = true;  
111:    }  
112:    def onServiceDisconnected(className: ComponentName) = {  
113:     // This is called when the connection with the service has been  
114:     // unexpectedly disconnected -- that is, its process crashed.  
115:     mService = null;  
116:    }  
117:   }  
118:   override def onStart = {  
119:    super.onStart()  
120:    // Bind to the service  
121:    Log.i("BAA", "Binding")  
122:    bindService(new Intent(this, classOf[BackgroundTimer]), mConnection, Context.BIND_AUTO_CREATE);  
123:   }  
124:   @Override  
125:   override def onStop = {  
126:    super.onStop()  
127:    Log.i("BAA", "Unbinding")  
128:    // Unbind from the service  
129:    if (mIsBound) {  
130:     try {  
131:      // Give it some value as an example.  
132:      val msg = Message.obtain(null,  
133:       BackgroundTimer.UNREGISTER)  
134:      msg.replyTo = mMessenger  
135:      mService.send(msg)  
136:      Log.i("BAA", "Sent message")  
137:     } catch {  
138:      case ex: Exception => Log.i("BAA", ex.getMessage())  
139:     }  
140:     unbindService(mConnection)  
141:     mIsBound = false;  
142:    }  
143:   }  
144:  }  

The first thing to notice is that we are using 2 Traits.  Actionable and MessageReceiver.  You can see, even with this simple app, we're composing functionality from small pieces, and we're reusing code from the Service.  I've never NEEDED multiple inheritance, but in this case, it sure is nice.  We've already seen MessageReceiver, but lets take a look at Actionable:


1:  package com.example.scaladoro.activity  
2:  import android.view.View  
3:  trait Actionable {  
4:   implicit def toRunnable[F](f: => F): Runnable = new Runnable() { def run() = f }  
5:   implicit def toOnClickListener(f: View => Unit): View.OnClickListener = new View.OnClickListener() { def onClick(v: View) = f(v) }  
6:  }  

Actionable simply holds 2 implicit definitions.  These allow us to use functions in our Activity instead of having to constantly create new Abstract inner classes.  Now when I want to run something on the UI thread, I just use the syntax on line 43.  No 'new' keyword, no class definition, no methods to mark @Override.  Just the code that will be run.  All the cruft that obfuscates what we're trying to do is gone.

Notice I had to use additional syntax to set the click listeners (line 21).  I defined the click listener functions in the activity, and Scala's compiler didn't like them until I wrapped them in the implicit.  It doesn't add a ton of code and I find it to be a much cleaner implementation of the state/strategy pattern than creating abstract classes, so I'm willing to live with it.

Take another look at the code. Once again, there is is very little 'boilerplate' and nice cohesion.  Once you understand the Scala syntax, its also a lot easier to read and to reason about what is going on than the equivalent Java code.  At least, it is for me.

If you are interested in seeing the app run, go ahead and download it.  I've posted it to the Play store:

Want to try the app out?  Download Campari Pomodoro.


Saturday, December 8, 2012

Scala And Android Were Made For Each Other

I've been experimenting with Scala for a while now, and the more I use it, the more I like it.  Scala isn't exactly what I would call an approachable language, but if you are familiar with Java or C# and you slowly work your way into it, Scala is really a joy to work in.

I also like to write apps for Android.  Since Scala runs on the JVM, it runs on Android, too.  Recently I've started to think that Google made a mistake using Java for Android.  It probably helped Android gain apps and popularity since thousands of developers could install the Eclipse Android Plugin and start coding, but that's the thing - Coding on Android is very different than coding, say, a Web app.  It's even quite different than coding a desktop app.  And it is because of the way that things should be written on Android that Java seems to be a poor fit.  All those thousands of programmers started writing apps - and did it wrong.

I know.  I made tons of mistakes.  As I read more about the platform and become more familiar with how things ran, it is clear that a lot of what I did often wasn't a best practice.  Some of what I did was just wrong.

This is where I get to the title of this post.  I recently experimented and wrote an application for Android using Scala.  I have to say, after writing the application this way, I don't ever want to go back. It is my sincere belief that Scala is a much better fit for writing applications on Android than Java.  To prove my point, I am going to go through the app I wrote and show you the Scala code. I am going to assume if you are reading this that you already have some familiarity with Android development so I will refrain from showing the Java alternative.

I'm also going to point out that I am in no way a functional programming expert.  As I said, I use Scala as a better Java.  My code continues to become 'more functional', but I'm sure this is not idiomatic Scala.  That's okay by be, though, because things are just easier.  To me, that's the best measure of how good the code is.

Background

We recently had half our staff move to an office in San Francisco.  Our company has always moved at a rapid pace, but with the additional overhead of working with a team 2 hours difference and across the US, I was feeling like I was getting distracted. I wanted to find a management technique that was simple and that would help me stay on track.  I picked the Pomodoro technique - it was simple. It suited me. It was invented by a programmer, and there were several apps in the Play store for me to use. Of course, I wanted to write my own anyway.

For the purpose of this app, all you need to know is that a Pomodoro is a 25 minute block of time where you concentrate on doing work. Since this is a pretty straight forward app to write, though, I thought I would implement it in Scala to see how it went.

If you want to know more about the Pomodoro Technique, you can visit the official Pomodoro Technique page or Buy the book on Amazon (convenient link on the left).




Application Definition

Here are the things I want the application to do:
  • Allow me to start a Pomodoro (a 25 minute block of time)
  • Play the ticker sound while in a Pomodoro (for some reason, hearing this helps me stay on track)
  • Play a bell when the Pomodoro finishes
  • Allow me to cancel a Pomodoro if I have to
  • Keep the Pomodoro timer running, even if I close the application 
Here are the constituent parts of my application:
  • Activity - Main activity, only Activity.  It has the text that shows you the time left and a button that changes states.  The button will either start or stop the timer.
  • Service - A background service that will run the timer task - counting down 
If you've done any Android programming in the past, you realize that even these simple requirements will result in a slew of callbacks, threads, anonymous inner classes, binders, messengers...need I go on?  Okay, that was a bit of an exaggeration, but not as exaggerated as it seems.

Let's think about this for a moment. In order to prevent ANR warnings we need to keep things off the main thread, which, means any communication with our service should be run in separate threads.  Allowing the service to run separately from the Activity (and allow it to potentially be started and called from any activity, even someone else's) will require it to be started and bound so we'll need a Binder and then we'll need to implement its callbacks. Then communication should happen with Messages so we'll need a Messenger and we'll need to implement its callbacks. Oh, and if we want to update the UI so users know whats going on, we need to then run updates from background threads on the UI thread, which, requires a Runnable.

When you add all this up, it makes for lots of  boilerplate code.  Thankfully, the language features of Scala make this less verbose, easier to write,  more understandable, and ultimately easier to maintain.  It also makes it much easier to write code that will follow Android best practices.

Now that we know the what and the how, let's talk code.

The Code


We know we want a bound service that we can send messages to.  When you read the Android docs on it, you'll see that there is a abstract inner class that implements Handler and is passed to a Messenger that is returned in the Services onBind method.

Wow, that was a lot to say.  It is also a lot of boilerplate code.  I wanted to move this to a common class so it was out of my way.  In Java we might make an Abstract base class.  But wait, the Activity in our application also needs a Handler and a Messenger, and if we Make an AbstractService, we could not use that code in an Activity. If we make an AbstractActivity, we cannot use it for our Service.   Here is the first place where Scala is quite handy.  I was able to make a Trait.  Traits are very powerful and I'm using the one below as a 'better interface', which, might be under-utilizing this great feature.  It serves its purpose well, however.

1:  trait MessageReceiver {  
2:   implicit def toIncomingHandler(f: Message => Unit): Handler = new Handler() { override def handleMessage(message: Message) = f(message) }  
3:    
4:   val mMessenger = new Messenger({ m: Message => 
5:    onMessage(m)  
6:   })  
7:    
8:   def onMessage(m: Message)  
9:  }  

Notice that I also used an implicit to reduce the need to declare an abstract inner class to handle the message.  I probably didn't save any code, but I like the way this looks far better than the Java alternative.

Now that we have the MessageReceiver defined, let's define our Service.  Before I show you the code, here are some things I want you to notice about the class:

  • We override onMessage and implement it.  This is the only code in this class that is related to receiving a message.  All the boilerplate has been moved to the Trait which can be used by both Activity and Service classes.
  • The start method has an internal method called timer that is recursive. This also happens to be tail recursive, and Scala is smart enough to unwind this, so it won't grow my stack.  
  • We run the timer in a background thread.  Notice that all we have to do is surround it with a spawn{} block.  (I omitted the imports, but you need to import scala.concurrent.ops._ to do this)


1:  case class BackgroundTimer extends Service with MessageReceiver {  
2:     
3:   var millis = 0L;  
4:   /** Keeps track of all current registered clients. */  
5:   var mClients = List[Messenger]()  
6:   var currentTime = "0:00"  
7:    
8:   val mediaPlayer = new SoundPool(2, AudioManager.STREAM_MUSIC, 0)  
9:    
10:   var tickId: Int = -1  
11:   var alarmId: Int = -1  
12:   var tickStreamId = -1  
13:     
14:   override def onMessage(m:Message) = {  
15:    m.what match {  
16:     case BackgroundTimer.REGISTER =>
18:       mClients ::= m.replyTo  
19:      }  
20:     case BackgroundTimer.UNREGISTER =>
21:      if (m.replyTo != null) {  
22:       mClients = mClients.remove(messenger =>
23:        if (messenger == m.replyTo) {  
24:         true  
25:        } else {  
26:         false  
27:        })  
28:      }  
29:     case BackgroundTimer.START >  
30:      start()  
31:     case BackgroundTimer.STOP =>
32:      //don't play the alarm bell  
33:      stop(true)  
34:    }  
35:   }  
36:    
37:   override def onStartCommand(intent: Intent, flags: Int, startId: Int): Int = {  
38:    Log.i("BAA", "Received start id " + startId + ": " + intent)  
39:    try {  
40:     tickId = mediaPlayer.load(this, R.raw.singletick, 1)  
41:     alarmId = mediaPlayer.load(this, R.raw.alarm, 1)  
42:    } catch {  
43:     case e: Exception => Log.d("BAA", e.getMessage())  
44:    }  
45:    Service.START_STICKY; // run until explicitly stopped.  
46:   }  
47:    
48:   /**  
49:    * Must override this to allow the service to bind to the Activity so we can start/stop timers  
50:    */  
51:   override def onBind(intent: Intent): IBinder = {  
52:    Log.i("BAA", "OnBind called")  
53:    return mMessenger.getBinder()  
54:   }  
55:    
56:   def start() = {  
57:    if (millis == 0) {  
58:     spawn {  
59:        
60:      var alarmStreamId = -1  
61:      try {  
62:       tickStreamId = mediaPlayer.play(tickId, 2.0f, 2.0f, 1, -1, 1.0f)  
63:      } catch {  
64:       case e: Exception => Log.d("BAA", e.getMessage())  
65:      }  
66:        
67:      def timer(millisLeft: Long): Unit = {  
68:       if (millis > 0) {  
69:        millis = millisLeft  
70:       }  
71:       val seconds = (millisLeft / 1000) % 60;  
72:       val minutes = ((millisLeft / (1000 * 60)) % 60);  
73:       currentTime = minutes + ":" + (if (seconds > 9) seconds else "0" + seconds)  
74:    
75:       if (millis > 0) {  
76:        mClients.foreach { messenger =>
77:         val response = Message.obtain(null, BackgroundTimer.TICK, 0, 0, currentTime)  
78:         messenger.send(response)  
79:        }  
80:        Thread.sleep(995);  
81:        timer(millisLeft - 995)  
82:       } else {  
83:        stop(false)  
84:          
85:       }  
86:      }  
87:      //now start it off...  
88:      millis = 1000 * 60 * 25  
89:      timer(millis)  
90:     }  
91:    }  
92:   }  
93:    
94:   def stop(forced:Boolean) = {  
95:    millis = 0  
96:    currentTime = "0:00"  
97:    mediaPlayer.stop(tickStreamId)  
98:    if(!forced)  
99:     mediaPlayer.play(alarmId, 0.2f, 0.2f, 1, 0, 1.0f)  
100:    mClients.foreach { messenger =>  
101:     val response = Message.obtain(null, BackgroundTimer.STOPPED, 0, 0, currentTime)  
102:     messenger.send(response)  
103:    }  
104:   }  
105:  }  
106:    
107:  /**  
108:   * Define an object to hold some statics  
109:   */  
110:  object BackgroundTimer {  
111:   val REGISTER = 1  
112:   val START = 2  
113:   val STOP = 3  
114:   val UNREGISTER = 4  
115:   val STARTED = 5  
116:   val STOPPED = 6  
117:   val TICK = 7  
118:  }   
119:    

I don't know about you, but this class looks very clean to me.  Almost all the code is directly related to what this class is intended to do with no messy boilerplate code for messaging or threading.  In fact, threading is now too easy -  just add a spawn block and done.  The 'business logic' is also very compact.  Since timer can be declared inside start, all the logic for actually running the timer is in one spot - no need to jump to a different section of code to see what's going on.

Want to try the app out?  Download Campari Pomodoro.

Next up, the Activity