Monday, October 25, 2010

Introduction to Android App Development in Scheme

This tutorial is based on the Kawa - Scheme Language Framework developed by Per Bothner. Kawa Scheme is used by Google's AppInventor framework. However Appinventor only allows you to develop using a visual interface. The tutorials here will show you how to develop Android Apps by writing code in Scheme. So let us jump into it straight away.

Here is the source code for a simple app that will display a TextView and show a Button. When you click the button it will display a Toast message.

(require 'android-defs)


(activity hello
  (on-create-view
    (android.widget.LinearLayout (this)
      orientation: android.widget.LinearLayout:VERTICAL
      view:
        (android.widget.TextView (this)
          text: "Hello Android, from Kawa Android!")
      view:
        (android.widget.Button (this)
          text: "Click Me!"
          on-click-listener:
            (lambda (v)
              ((android.widget.Toast:makeText
                (this)
                "Beep Bop! You clicked me!"
                android.widget.Toast:LENGTH_LONG):show))))))

You can see how simple and functional the whole code is. Even if you don't know scheme you can figure what is going on.

To get this code working on linux you will need to follow Per Bothner's blog post on how to set up your android development environment. Make sure you use the latest svn version of Kawa. For windows users you can follow the same equivalent procedure and it works. Get the hello example shown at the site working for you first. Copy and paste the code above into your hello.scm file and create the app.

Now for some explanation of the code. First we load the android-defs library, which loads some android definitions.
(require 'android-defs)

From Kawa Scheme we can interact with java virtual machine directly. Next we create an scheme expression to call the 'activity' macro. Scheme expressions have the form
(function & args)
Our expression is
(activity hello (....))
The activity macro creates an android.app.Activity with its first argument as name, which in this case is 'hello', and the second argument is an expression that will evaluate to an android.view.View object. The second argument in this case is the expression
(on-create-view ...)
which is also a macro that evaluates its argument expression and calls the setContentView method of the activity with the evaluated view. The rest of the code is for generating the view object.

In Kawa we can instantiate an instance of a class with this syntax

(MyClass keyword1: value1 ... kewordN: valueN)

where keyword corresponds to a field or method name. In the case of a field it will set the value of the field, and in case of a method it will call the method with the value.

In case you pass a lambda expression (anonymous function) as a value then Kawa will call the method with a corresponding anonymous class.

Also keywords need not match the method names exactly. Keyword 'text' will make the compiler look for the "setText" "addText" methods. "on-click-listener" gets translated to "onClickListener".

So this is what happens in the rest of the code. First we create an instance of the LinearLayout
android.widget.LinearLayout (this)
to which we pass keyword value pairs. The first keyword sets the orientation. Then we call 'view' twice (Kawa will call the addView method of LinearLayout) passing it the TextView instance the first time and the Button instance the second time.

We create the TextView and Button object similarly. The on-click-listener of the Button object is passed a Lambda function which in turn instantiates a Toast object using its static method makeText. Kawa will automagically create the android.view.View.OnClickListener class as required by the onClickListener function of the button.

Now let us look at this part of the code.

              ((android.widget.Toast:makeText
                (this)
                "Beep Bop! You clicked me!"
                android.widget.Toast:LENGTH_LONG):show))))))

First we call the makeText static method of the android.widget.Toast class which returns an instance of the Toast class and we immediately call its ':show' method. In kawa to access a field or method of an object use the ':' notation.

6 comments:

  1. Any chance you could comment on the overhead ("binary"/deployment package size, runtime speed) on writing and deploying Android applications this way? Thanks.

    ReplyDelete
  2. Am I seeing this right: does your example have two variables both assigned the same keyword (view:) ? In Lisp this is illegal. In Scheme, legal I suppose but certainly very much frowned upon.

    ReplyDelete
  3. Yes there is a deployment over, i am currently estimating around 1 MB. I don't see any degradation of run time speed with the kind of apps I have done.

    Regarding multiple usage of keywords here (view:), I view this as a special case, (this is not really map semantics) so it should be ok.

    You could also pose this question on the kawa mailing list for a more in depth view. The link to the mailing list is here.
    http://www.gnu.org/software/kawa/Mailing-lists.html

    ReplyDelete
  4. I am using Komodo Edit, without any IDE. Thats the way I like to work on this.

    ReplyDelete
  5. Just to let everyone know, in addition to Kawa Scheme, the latest version of Bigloo Scheme 3.5a supports Android as well: http://www-sop.inria.fr/mimosa/fp/Bigloo/

    ReplyDelete