giant robots smashing into other giant robots

Written by thoughtbot

lolconomy

Scala: A Better Java for Android

Stop writing Java for your Android apps!

There are a slew of ways to build Android apps. The original Java way reigns supreme but some alternatives are C++, Mirah, Python, Titanium Appcelerator, Corona, and so on.

And there’s Scala.

Scala can be thought of as a better Java. To start with, you don’t need as many semicolons. But Scala gives you the power of modern abstractions. Traits, implicits, type-checked null, blocks—everything you really need to get some solid coding done.

(Briefly, the magic Android sauce is the scalaforandroid project.)

As an example of what Scala can do for your app, take this simple project: a button which, when pressed, shows a toast:

package com.thoughtbot.helloscala

import _root_.android.app.Activity
import _root_.android.os.Bundle
import _root_.android.widget.Toast
import _root_.android.view.View
import _root_.android.view.View.OnClickListener
import _root_.android.widget.Button

class HelloActivity extends Activity {
  override def onCreate(savedInstanceState : Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)

    val button = findViewById(R.id.button).asInstanceOf[Button]
    button.setOnClickListener(new View.OnClickListener() {
      def onClick(v : View) {
        Toast.makeText(this, "You have clicked the button", 
        Toast.LENGTH_LONG).show()
      }
    })
  }
}

This is basically the Java version without semicolons. But we can spruce it up with a trait and an implicit:

package com.thoughtbot.helloscala

import _root_.android.app.Activity
import _root_.android.view.View
import _root_.android.view.View.OnClickListener

trait FindView extends Activity {
  def findView [WidgetType] (id : Int) : WidgetType = {
    findViewById(id).asInstanceOf[WidgetType]
  }
}

class ViewWithOnClick(view : View) {
  def onClick(action : View => Any) = {
    view.setOnClickListener(new View.OnClickListener() {
      def onClick(v : View) { action(v) }
    })
  }
}

object FindView extends Activity {
  implicit def addOnClickToViews(view : View) = 
    new ViewWithOnClick(view)
}

This adds an onClick method to Views and a findView method for Activities. Life just got a little more functional:

package com.thoughtbot.helloscala

import _root_.android.app.Activity
import _root_.android.os.Bundle
import _root_.android.widget.Toast
import _root_.android.view.View
import _root_.android.widget.Button
import FindView._

class HelloActivity extends Activity with FindView {
  override def onCreate(savedInstanceState : Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)

     findView[Button](R.id.button).onClick { view : View =>
        Toast.makeText(this, "You have clicked the button", Toast.LENGTH_LONG).show()
    }
  }
}

Take this concept as far as you need: a doInBackground method for functions, a withState-like function for PreferenceManager, a caching wrapper for URLs—the sky is the limit here.

So what’s stopping you from using Scala for your Android app?

If you’re interested in learning more about Android development, sign up to be notified the next time we run our Android workshop.

plapier

Designing Menu Icons for Android Devices

Recently we took on a client project which entailed building an Android app. The client delivered to us a set of sixteen 30x30 pixel PNG icons for use in the app. The icons displayed well on low-density screen devices, such as the Samsung Moment, but they were not large enough to accurately retain detail on higher density screen based devices, e.g. HTC G1 and the Nexus One. The solution was to redraw the icons in vector format and size them for the various screen densities.

Android uses a number of resource directory qualifiers for controlling which density-specific icon will be displayed for each device. In this case I focused on creating icons for low-density (ldpi), medium-density (mdpi), and high-density (hdpi) screens. Effectively, this means three specific sizes of each icon are needed—36x36 pixel, 48x48 pixel, and 72x72 pixel icons. It is worth noting that the new icon document resolution should remain at 72 pixels/inch for all icons, including high-density screen icons (don’t be fooled by the android density numbers).

The Process

The process began by importing all sixteen icons onto a single document in Adobe Fireworks. I used Fireworks’ vector tools to retrace each icon. Rather than using the merging tools on the vector paths, I used Rogie King’s Alpha converted vector groups technique to preserve a high amount of editing for the icons. The new vector paths can be seen in the icons below.

After vectorizing all sixteen of the original icons, I then set out to resize them. The Android developer docs contain useful guidelines for creating menu icons with consistent visual weight across all devices.

To maintain pixel perfect appearance, tweaks will often need to be made when vectors are resized up or down. The alpha converted vector groups helped facilitate the tweaking process. The icons below are sized for their respective screen densities.

After all the icons are resized and exported as transparent PNG images, they must be placed in their respective folder in the resources directory—drawable-ldpi, drawable-mdpi, drawable-hdpi. The filenames must remain the same for each icon, but be stored in the mentioned density-specific resource directories. Android devices will load the proper resources according to the screen density of the device.

Below are a few ‘before and after’ views of a few icons that went through the process. The icons appear much crisper, have sharper edges, and are now fully transparent. The end result provides a much more professional looking Android App, whereas the icons enhance the menu navigation by providing the user with a clearer interpretation of each graphic symbol.