This is a shame. Using Scala macros, I made a new function put(Any*) on Intent, that can be used like this:

new Intent().put(valueA, valueB, valueC)

Intents can be started

To start an activity from the intent above, we are writing like this:

startActivity(SIntent[MyActivity].put(valueA, valueB, valueC))

This is concise, but not really readable. From this version, we can rewrite it:

new Intent().put(valueA, valueB, valueC).start[MyActivity]

This looks more natural because it can be translated one-to-one in plain English:

Create a new Intent, and put values A, B, and C. Then, start the MyActivity.

Wrap or fill

I found that I am using layout properties wrap and fill very frequently. Because layout properties should written in <> blocks, we have a lot of <> and <> in our code. These idioms makes sense in terms of consistency, but not very pleasing. Because Scaloid is not stingy with providing shorthands, I dropped out <> from it.

Now we can specify 'wrap-ness' of a TextView like this:

textView.wrap

This looks trivial at first. However, think about how many times you are using it.

Additionally, we provide functions fw and wf, that is equivalent to <> and <> respectively.

Drops support Scala 2.10

Scaloid 3.6 is built on Scala 2.11.3, so you can use it with other Scala 2.11.x versions. From this version, I drops Scala 2.10 support to use full potential of recent improvements on macros.

Building Scala 2.11.3 on Android

I've found that building Android apps with Scala 2.11.3 (and 2.11.4) results more proguard warning, that prevents Android projects from being built. The error messages are:

Tuesday, April 22, 2014

I've found that newly introduced class scala.collection.mutable.AnyRefMap and mutable.LongMap are using java.util.Arrays.copyOf(...), that is available only on Android API level 9 and above.
This means that your Android app might not work with Froyo devices if you build it with Scala 2.11. Because the current market share of the API level < 9 is less than 1 percent, this limitation is not serious.

However, if you stick to support older Android devices, here is a workaround:

Add -dontwarn scala.collection.mutable.** in your proguard settings.

Do not use scala.collection.mutable.LongMap and mutable.AnyRefMap. Make sure these classes not be called in transitive way.

Functional programming rocks. However, legacy Java libraries prevent us to stay in such an ideal world. The job objective of Scaloid is to help write Android code in more elegant style. Although Scaloid doing good job on layout building, I haven't do much things about databases yet.

There are many DB frameworks for Scala. If you writing an app relying on DB extensively, I recommend to use one of them. But when you are using the built-in Sqlite just for storing some casual data, it is not a bad idea that using Android APIs for database access. The biggest problem in this case is that the code is not neat, because of its API architecture. Let's see a common example:

We have to use variable for the return object because the android.database.Cursor does not provide Scala-compatible iterator. Another clutter is close() call in try-finally section. This can be reduced in more functional-style:

By declaring implicit def cursor2RichCursor(c: Cursor) = new RichCursor(c), or extending the trait org.scaloid.common.DatabaseImplicits to your class, The android.database.Cursor implicitly converted into RichCursor, which implements Iterable[Cursor]. Now, we can use many useful iterator methods such as map, foreach, and foldLeft.

I also introduce a function closeAfter[T](body: RichCursor => T):T that closes the cursor after evaluating its parameter.

One of the important thing that can be missed is to convert the mapped result into a List. Iterator.map returns another Iterator that evaluate the original iterator(RichCursor in this case) on demand. The implementation of Iterator.map looks like this:

So if we missed to convert the iterator to List or other form, newly created Iterator generated from the mapping will evaluate the Cursor that is already closed, and vomit the exception. This issue is too detailed, and very easy to miss at first. What we just need is iterate each rows and map a row with a domain object, and forget about cursor. So I created a wrapper function that does this mission simply:

As the name of the function implies, it does very simple form of Object-Relation-Mapping.

In other cases, we often need just one record from the query result. For example, getting count of something, or retrieving some column about a particular user. Even such a simple requirement, we have to write a verbose code as: