2013年6月25日火曜日

[Android]ListViewの選択されたアイテムの背景色を変更

ListViewの行をタップして選択した後も選択された行の背景色を変えたままにする方法を紹介します。

res/drawable/list_item_selector.xml

タッチした時とタッチ後の色を変えるためのselectorを定義します。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_selected="true"
        android:drawable="@color/selected_list_item_color"/>
  <item android:state_pressed="true"
    android:drawable="@color/selected_list_item_color"/>
  <item android:drawable="@color/default_color"/>
</selector>

res/values/colors.xml

list_item_selector.xmlで参照する色を定義します。

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="selected_list_item_color">#ffd33f</color>
  <color name="default_color">#000000</color>
</resources>

res/layout/list_row.xml

ListViewの行を定義するレイアウトのbackgroundに上記のlist_item_selectorを設定します。

<?xml version="1.0" encoding="utf-8"?>    
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:background="@drawable/list_item_selector"
    >
  <TextView
      android:id="@+id/symbol_text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="symbol"
      />
</RelativeLayout>

scala/MainActivity.scala

ListViewのItemClickListenerでクリックされたアイテムに対してsetSelected(true)を呼び出します。
こうすることでlist_item_selectorで設定したstate_selected=”true”の条件にマッチするようになります。

val unitList = findView(TR.unit_list)
unitList.setOnItemClickListener(new OnItemClickListener {
  def onItemClick(parent: AdapterView[_], view: View, pos: Int, arg3: Long) {
    view.setSelected(true)
  }
})

2013年6月20日木曜日

ライブラリをプリロードして(ProGuardを無効にして)ScalaによるAndroid開発を高速化

最近ScalaでAndroid開発を始めました。
やり方は解説サイトが色々あるのでそちらを参考にして下さい。

まだたいしたことはしていませんが、今のところ大きなトラブルもなくScalaのパワーを生かして快適に開発ができています。

ただ実際に開発を行うと気づくと思いますが、ビルドにものすごく時間がかかります。
これはビルドのたびにProGuard処理が走り、必要なScalaのライブラリもコンパイルしてapkに含めているためです。
従ってProGuardを無効にするとScalaのライブラリが実行時に見つからずエラーとなります。
これを回避するためにAndroidProguardScalaというEclipseプラグインがありますが、僕はIntelliJ+sbtで開発しているため使用できません。

もう1つの解決策はScalaのライブラリをあらかじめAndroid端末にプリロードしておくことです。
幸い開発中のandroid-pluginの最新版ではこれが簡単に行えるようになっていたので試してみました。
ちなみにこの方法はルート化が必要となります。

手順は基本的にはここで解説されている方法に従えばOKです。

1. 0.7-SNAPSHOTバージョンを使用できるようにする。

適当なディレクトリで以下を実行

$ git clone https://github.com/fxthomas/android-plugin.git
$ cd android-plugin
$ git checkout rewrite-cleanup
$ sbt publish-local

2. plugins.sbtを編集

addSbtPlugin("org.scala-sbt" % "sbt-android" % "0.7-SNAPSHOT")

3. Build.scalaの書き方が大分変わっているので、この辺を参考に書き換える

参考までに僕のプロジェクトは以下のようになっています。

 import sbt._
 import Keys._
 import sbtandroid.AndroidPlugin._

 object AndroidBuild extends Build {
   // Global settings for all projects
   val globalSettings = Seq(
     name := "ConvertBox",
     version := "0.1",
     versionCode := 1,
     scalaVersion := "2.10.1",
     platformName := "android-15",
     keyalias := "key_android",
     javacOptions ++= Seq("-encoding", "UTF-8", "-source", "1.6", "-target", "1.6")
   )

   // Main project
   lazy val main = AndroidProject("main", file("."), settings=globalSettings)

   // Android instrumentation tests
   lazy val tests = AndroidTestProject("tests", file("tests"), settings=globalSettings)
     .dependsOn(main % "provided")
     .settings(name := "ConvertBoxTests")
 }

4. 一旦’sbt start’を実行して以前のようにProGuard付きでビルドできることを確認する

5. ルート化された端末、もしくはエミュレータを用意して下記を実行

  • 実機

    sbt> preload-device
    
  • エミュレータ

    sbt> preload-emulator avdName
    

上記のコマンドを成功させるためにはルート権限を持ったシェルが実行可能である必要があります。
‘adb root’を実行して’adbd cannot run as root in production builds’と表示されたらルート権限を持ったシェルを直接は実行できないようになっているので、RootAdbをインストールするなどして実行できるようにして下さい。

成功すると/system/framework/にscala-library-2.10.1.jarがあるはずです。

6. ProGuardを無効にしてビルドできるか確認

sbt> preload:start

うまくいけばProGuard処理のメッセージが出ずにビルドが終了し、アプリケーションも正常に実行されるはずです。

どれくらい速くなった?

環境は以下の通りです。

  • OS: Mac OS X Mountain Lion (10.8.4)
  • CPU: Intel Core 2 Duo 2.66 GHz
  • Memory: 8 GB (1067 MHz DDR 3)
  • Disk: SSD

‘sbt start’(ProGuard有り)の処理時間

image

‘sbt preload:start’(ProGuardなし)の処理時間

image

46秒から9秒まで高速化されました!約5倍の速度アップです!
これでかなり開発のターンアラウンドタイムが短くなりますね!

注意事項

当然ですがアプリをリリースする際にはProGuardを有効にしてビルドしたものを配布して下さい。他の人の実機にはScalaのライブラリなんて入ってませんから・・・。

参考サイト