Channels ▼
RSS

Developing Android Apps with Scala and Scaloid: Part 1


Scaloid is an open-source library that enables Scala developers to create Android apps without having to migrate to Java. Scaloid takes full advantage of many of Scala's features, such as the efficient way of creating Domain Specific Languages (DSLs), implicit conversions, pattern matching, and type safety. Scaloid proposes a novel method of developing Android apps, which is worth a second look. In this lead article of a two-part series on Scaloid, I explain some of its most interesting features.

Simplifying Android Code with Scala Features

Scaloid focuses on simplifying and reducing the required Android code as much as possible while taking advantage of type safety. You can make incremental use of many Scaloid features in your Android projects because you can mix Scala and Scaloid with Java and the Android API.

Think of Scaloid as a library that provides shortcuts to tasks that usually require a large amount of code. Scaloid replaces the XML layout description required by the Android SDK as well as the Java code that specifies the logic with a single piece of Scaloid code that uses a Scala DSL. In this way, you can build a UI layout by writing type-safe Scala code and wire your logic into the layout. However, you will use Scaloid to access widgets defined in XML layouts, so you can continue working with XML layouts if you don't want to make a big paradigm shift in your Android development process.

There is an automatic layout converter that translates an Android XML layout description into a Scaloid layout at http://layout.scaloid.org. The converter is still a beta version and might lose some precision during translation. However, the converter allows you to easily start working with Scaloid layouts using your existing knowledge of Android XML layouts, and you can still use the graphical layout designers provided by your favorite IDE.

Figure 1 shows a very simple Android UI with two TextView widgets, two Password fields and a Button widget in a LinearLayout with a vertical orientation.

Scaloid
Figure 1: The graphical layout designer in Eclipse with an Android UI preview.

The following code shows the XML for the UI. It includes hardcoded strings in order to make it easy to understand the conversion to a Scaloid layout. However, as you already know, you shouldn't use hardcoded strings for the UI in real-world apps.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/item_detail_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ItemDetailActivity"
    tools:ignore="MergeRootFrame" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Enter your password" />

        <EditText
            android:id="@+id/password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPassword" >

            <requestFocus />
        </EditText>

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Repeat your password" />

        <EditText
            android:id="@+id/passwordConfirmation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPassword" />

        <Button
            android:id="@+id/login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Sign in" />

    </LinearLayout>

</FrameLayout>

If you paste the XML code in the layout converter at http://layout.scaloid.org and you click on Submit, the results of the translation will be the following lines of Scala code:

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

  contentView = new SFrameLayout {
    this += new SVerticalLayout {
      STextView("Enter your password").<<.wrap.>>
      SEditText().inputType(TEXT_PASSWORD)
      STextView("Repeat your password").<<.wrap.>>
      SEditText().inputType(TEXT_PASSWORD)
      SButton("Sign in")
    }.<<.fill.>>
  }
}

The layout description with Scaloid (see Figure 2) is greatly reduced compared with the XML code. As you might guess by reading the code, the Scaloid UI definition adds an S prefix to the equivalent Android SDK classes. For example, Scaloid defines the SFrameLayout class in the org.scaloid.common package. SFrameLayout is a concrete helper class of android.widget.FrameLayout.

Scaloid
Figure 2: An Android device emulator displaying the UI generated with the Scaloid code.

The Scala code requires the import org.scaloid.common._ import line, and the overridden onCreate method must be placed in a class that extends the SActivity (org.scaloid.common.SActivity) trait. I'll discuss the creation of a Scaloid project from scratch later, but for now, I want to focus on the way Scaloid defines the UI.

The classes with the S prefix, known as prefixed classes, allow you to use Scala-style getters and setters because they provide the necessary implicit conversions. In addition, these classes provide the instance of Context as an implicit parameter. As you already know, there are many methods in the Android API that require an instance of the Context class, and the implicit parameter simplifies the usage of these methods in the prefixed classes. You can declare an implicit value to represent the current context or extend the SContext trait that defines the implicit value. Because the code defines the onCreate method within a class that extends SActivity, the implicit value is already defined. SActivity extends Activity with SContext and other traits, as you can see in the following declaration:

trait SActivity extends Activity with SContext with TraitActivity[SActivity] with Destroyable with Creatable with Registerable {

By reading the Scala code, it is easy to see that you have a SFrameLayout with a SVerticalLayout that includes the following five widgets, and you don't need to scroll because the code requires just a few lines:

  • STextView
  • SEditView
  • STextView
  • SEditView
  • SButton

All the prefixed classes that extend Android widgets have a companion singleton object that implements apply methods with different parameters, which create the new component and append it to the layout context that encloses it. For example, the SButton class is the helper class of android.widget.Button, and there is also an SButton object with four apply methods. You need only write the following line to add a button and set its text to "Sign in."

SButton("Sign in")

This way, you can take advantage of the shortcuts and you don't need to write more code to achieve the same effect, as in the following two lines:

button = new SButton() text "Sign in"

this += button

In the following line, notice the use of two methods: << and >>:

STextView("Enter your password").<<.wrap.>>

The << method returns an object of the android.view.ViewGroup.LayoutParams type that provides many methods and setters in the context of the inner-most layout. In this case, the inner-most layout is SVerticalLayout. Scaloid uses the following default values for the LayoutParams object:

  • width: FILL_PARENT
  • height: WRAP_CONTENT

The default code would be similar to the following line:

STextView("Enter your password").<<(FILL_PARENT, WRAP_CONTENT)

Scaloid uses two methods to provide shortcuts for frequently used values of width and height:

  • fill: Sets width to FILL_PARENT and height to FILL_PARENT.
  • wrap: Sets width to WRAP_CONTENT and height to WRAP_CONTENT.

The following lines are equivalent. One of them uses wrap and the other sets the width and height values:

STextView("Enter your password").<<.wrap

STextView("Enter your password").<<(WRAP_CONTENT, WRAP_CONTENT)

The >> method allows you to return the original object. Thus, the following line creates a new TextView widget, sets its text to "Enter your password," appends the widget to the enclosing SVerticalLayout, sets the width and height values for its LayoutParams object, and finally assigns the STextView instance to the textView1 variable.

val textView1 = STextView("Enter your password").<<.wrap.>>

In the Scaloid code that defines the UI, you will notice that the SVerticalLayout declaration ends with the following line:

}.<<.fill.>>

This way, the code sets the width and height values for the LayoutParams object of the SVerticalLayout instance, and then goes back to this instance.

You can also interact with a UI defined with classic XML by using the find method and specifying the widget type. For example, the following line retrieves the signIn button from the UI definition:

val button = find[Button](R.id.signIn)

This is equivalent to the following longer code:

val button = findViewById(R.id.signIn).asInstanceOf[Button]

The clear disadvantages of accessing UI widgets with either the find or findViewById methods are that the code is not type-safe and you have to track the widget type. If you use the wrong widget type, there isn't going to be a compile-time error.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video