2009-11-26 10:26 墳墓 (Brian Hsu)
退伍了,終於有比較多的時間可以東摸西搞了,想當然爾,現在的我想玩的,就是 Scala + Android 啦!
Android 確實是個很不錯的平台,可是也有他弱的地方,其中我最不喜歡的,就數 Content Provider 啦。
在 Content Provider 的架構下,的確可以達到不同應用程式間溝通的的做用,可是操作的階層實在是太低了,竟然直接動到資料庫的指標去了。
這對於已經漸漸習慣了 Functional 的我而言,真的是很痛苦啊,想到要在那邊 move 來 move 去,就一整個煩人。
幸好,這個時候,很強大的 trait 就登場啦,只要下面短短幾行的程式,馬上就可以把 Cursor 變成 Functional 啦!
class CursorSeq (cursor: Cursor) extends Seq[Cursor]
{
require (cursor.moveToFirst)
override val length = cursor.getCount
override val elements = new Iterator[Cursor] {
override def hasNext = !cursor.isLast &&
!cursor.isAfterLast &&
!cursor.isClosed
override def next : Cursor = {
cursor.moveToNext()
cursor
}
}
override def apply (n: Int) : Cursor = {
cursor.moveToPosition (n)
cursor
}
}
然後,再配上一些 Wrapper class……
case class ReminderItem private (id: Int, title: String,
description: String, triggerTime: Int,
maidID : String)
{
def uri : Uri = Uri.parse (Reminder.ContentUri + "/" + id)
}
object ReminderItem
{
private def get (cursor: Cursor) : Option[ReminderItem] =
{
if (cursor == null) {
return None
}
val colID = cursor.getColumnIndex (Reminder.ID)
val colTitle = cursor.getColumnIndex (Reminder.Title)
val colDescription = cursor.getColumnIndex (Reminder.Description)
val colTriggerTime = cursor.getColumnIndex (Reminder.TriggerTime)
val colMaidID = cursor.getColumnIndex (Reminder.MaidID)
val id = cursor.getInt (colID)
val title = cursor.getString (colTitle)
val description = cursor.getString (colDescription)
val triggerTime = cursor.getInt (colTriggerTime)
val maidID = cursor.getString (colMaidID)
Some (ReminderItem (id, title, description, triggerTime, maidID))
}
def getAll (context: Context) : Seq[Option[ReminderItem]] =
{
var result : Seq[Option[ReminderItem]] = Nil
val cursor = new CursorSeq (context.getContentResolver.
query (Reminder.ContentUri,
null, null, null, null))
for (row <- cursor) yield get (row)
}
}
就可以寫出 Functional,並且超簡潔的程式啦!例如:
val item = ReminderItem.getAll.filter (_ != None) // 取出標題是 Hello 的 ReminderItem item.filter (i => i.title == "Hello") // 取出所有 ReminderItem 的 Title item.map ( i => i.title)
這樣比起直接下 Query 來得清楚多囉。

回響