Scala+Android小ネタ集
(この記事は Scala Advent Calendar jp 2010 の5日目です。)
Scala+Androidで過去にはまったことなどを小ネタとして紹介します。
Androidに限らず、JavaのライブラリをScalaから使用する上でも役にたつかも。
java.lang.Classのインスタンスを取得する
ScalaではclassOfを使って取得できます。
Androidでは明示的Intentを作成するときなどに使います。
// Javaの場合 new android.content.Intent(this, HogeService.class)
// Scalaの場合 new android.content.Intent(this, classOf[HogeService])
scalaの予約語とおなじ名前のメソッドがあってコンパイルエラーになる
android.content.UriMatcherにはmatchメソッドがあってこれがscalaの予約語matchとかぶってコンパイルエラーになります。
そういう場合は`(バッククォート)を使ってください。たとえばこんな感じになります。
uriMatcher.`match`(url) match{
// case ...
}
java.lang.Threadのyieldメソッドとかも同じはずです。
Javaの<?>はScalaでどう書くのか
[_]です。
listview.setOnItemClickListener( new OnItemClickListener(){ override def onItemClick(av:AdapterView[_] , view:View, pos:Int, id:Long){ // ... } })
Javaクラスのstatic field
Javaクラスを継承したとき親クラスのstatic fieldにはクラス修飾なしではアクセスできません。
Androidの場合だとServiceを継承してonStartCommandでreturn START_STICKYなどと書くとコンパイラに怒られてしまいます。
return Service.START_STICKYと書く必要があります。
これはどういうことなのでしょうか。static fieldはScala的にはコンパニオンオブジェクトに属しているとみなされる、とかそういう理由でしょうか?(テキトウ)
メンバとしてボタンなどの画面要素を保持する
AndroidではonCreateの前に画面要素を取得しようとすると例外を投げられてしまいます。
なのでメンバとして画面要素を保持したい場合はlazy valを使いましょう。
class HogeActivity extends PreferenceActivity { private lazy val label = findPreference("label").asInstanceOf[EditTextPreference] // ... }
おまけ android.database.CursorをIteratorに
android.database.Cursorはそのままだといかにも手続きっぽいのでIteratorにimplicit conversionしてやるとScalaっぽい感じ(?)になります。
IteratorにするにはhasNextとnextさえ定義してやればよいので簡単です。
object AndroidHelper { import android.database.Cursor private object EmptyCursorIter extends Iterator[Cursor]{ def hasNext = false def next:Cursor = throw new java.util.NoSuchElementException() } private class CursorIter(cur: Cursor) extends Iterator[Cursor]{ def hasNext = !cur.isLast() def next:Cursor = if (cur.moveToNext) cur else throw new java.util.NoSuchElementException() } implicit def cursorToIterator(cur: Cursor): Iterator[Cursor] = if(!cur.moveToFirst) EmptyCursorIter else{ cur.moveToPrevious new CursorIter(cur) } }
これでCursorに対してforeachやmapが使えるようになります。
しかし調子にのってloan patternとか使って
def hogeList = using(getCursor()){ c => c.map( /* ... */)}
こんな風にすると、mapが実際に評価されるときにはCursorが閉じてたりなんかして悲しいことになったりするので要注意です。