kotlinAndroidLibを使ってみた。

以前にkotlinでAndroidするには?でググっていたら、kotlinAndroidLibというのがAndroidライブラリプロジェクトとしてgithubで公開されていました。
BatteryCrystalをkotlinで作り直した後に、試してみようと考えていたので、早速試してみました。

github: kotlinAndroidLib

使ってみたところ、コードが簡潔になってすごくいいです。
ただ、kotlinのバージョンが古いときに作られたライブラリプロジェクトで、現在はあんまりメンテナンスされてないようで、最初に使おうとしたら型チェックが通らなくてダメだったので、エラーになった部分は全部コメントアウトして使っています。ちなみにエラーになった部分はSQLite系やCursor系でした。

さて、kotlinAndroidLibを使った例を示します。
自分のコードで使っているので、IntentFilterをみせようと思います。
まず、Javaのコードです。

IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
registerReceiver(mReceiver, filter);

次に、kotlinのコード。

val filter = IntentFilter()
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
registerReceiver(mReceiver, filter)

最後に、kotlinAndroidLibを使ったkotlinのコード

registerReceiver(mReceiver, IntentFilter{
  addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
})

ちょっとスッキリした感じに書けます。

次に、匿名クラスのBroadcastReceiver。
Javaだと以下のような感じですね。

private BroadcastReceiver mReceiver = new BroadcastReceiver(){
  @override
  public void onReceive(Context context, Intent intent) {
    // 処理
  }
}

kotlinだと、こう。

private val mReceiver = object : BroadcastReceiver(){
  public override fun onReceive(context : Context?, intent : Intent?) {
    // 処理
  }
}

さらに、kotlinAndroidLibを使ったら、こう。

private val mReceiver = BroadcastReceiver{(context, intent) ->
  // 処理
}

だいぶ簡潔になりました。

BatteryCrystalのapkのサイズを比較すると、

Java: 1.1MB
kotlin: 1.3MB
kotlinAndroidLib: 1.4MB

くらいだったので、Javaにくらべると多少大きくなるものの、今の端末の容量であれば全然問題ないんじゃないかなーと思います。また、kotlinを使っている人にとっては利点こそはあっても悪い点はないのではないかなーと思います。自分の場合はいまいちまだkotlinに慣れていないので、つまずくことがまだ多いですが、コードを簡潔に書けると楽しいので、それだけでも使ってみてよかったなと思います。


kotlinでAndroidアプリを作り直したのでTipsを少々。

Google Playにkotlinで作り直したBatteryCrystalをリリースしてみました。
Javaで作られたアプリをKotlinで作り直して行く上で、とてもイライラもしつつも、面白かったです。

なので、kotlinでAndroidアプリを作るためのTipsを書いていこうかなと思います。
まぁ正直なところ、自分のための備忘録ですw

その前にアプリの紹介を少々。

BatteryCrystalは、バッテリーの残量を表示するウィジェットです。また、ウィジェットをタップすると、WiFiやBluetoothやGPSのON,OFFや、マナーモードの切り替えなどができます。ウィジェットがメインのアプリなので、普通のアプリとはちょっと違いますが、そのためいろいろと楽しめました。

Intentを作るには?

次のActivityを呼び出すために、Intentを作りますよね。しかし、kotlinではどうやればいいのかわからなくてハマりました。正解は、以下のようになります。

val intent = Intent(getApplicationContext(), javaClass<OtherActivity>())

定数を作るには?

Javaだと定数は以下のように定義します。

class MainActivity extends Activity {
    public static final String HOGE = "HOGE";
    private final String PIYO = "PIYO";
}

Kotlinでは、以下のようにします。

class MainActivity() : Activity() {
  private val PIYO = "PIYO"
  class object {
    val HOGE = "HOGE"
  }
}

staticメソッドを定義するには?

これも定数と同様に、class objectで定義します。
まず、Javaだとこうですね。

class MainActivity extends Activity {
    static public String hoge(String piyo) {
        return "hoge " + piyo;
    }
}

MainActivity.hoge(“piyo”); で呼び出しますね。

kotlinだとこうなります。

class MainActivity() : Activity() {
  class object {
    fun hoge(piyo : String?) : String? {
      return "hoge $piyo"
    }
  }
}

MainActivity.hoge(“piyo”) で呼び出せます。

匿名クラスを作るには?

バッテリーの残量が変わったらBroadcastが走りますね。それを拾うBroadcastReceiverをメンバ変数に定義しているのですが、それの定義方法を紹介します。
まず、Javaだとこう。

// mReceiverはMainActivityのメンバ変数とする
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @override
    public void onReceive(Context context, Intent intent) {
        // 処理
    }
}

kotlinだとこうなります。

private val mReceiver = object : BroadcastReceiver() {
  public override fun onReceive(context : Context?, intent : Intent?) {
    // 処理
  }
}

switch文を作るには?

kotlinには、switch文ではなく、whenをつかいます。
まずはJavaで。

String test;
switch(batteryState) {
    case 0:
    case 1:
        // 処理1
        test = "hoge";
        break;

    case 2:
        // 処理2
        // 複数行にまたがる処理
        String a = "pi";
        String b = "yo";
        test = a + b;
        break;

    case 3:
        // 処理3
        test = "fuga";
        break;

    default:
        test = "kotlin"
        break;
}

kotlinでは、こうなる!しかも、whenなので、戻り値を受け取れるので、こう書けます!
まるでRubyのcase文ですね。これだけですごくいいなぁ〜と思いました。

val test = when(batteryState) {
  0, 1 -> "hoge"
  2 -> {
    val a = "pi"
    val b = "yo"
    a + b // 最後のが戻り値になります
  }
  3 -> "fuga"
  in 4..10 -> "range" // 範囲を表すこともできる!
  else -> "kotlin"
}

kotlinで開発する場合は、IDEはIntellijだけになりますが、kotlinの開発元はIntellijを作っているJetBrainsなので、IDEで困ることはありません。また、IntellijでAndroidアプリを作るのに困る点も別にありません。よっぽどEclipseに慣れているということであれば別かもしれませんが…。

次に1から作るアプリはkotlinでやってみようかなと思います。


Cucumberで日本語でstepからstepを呼び出す

The RSpec Book読書会を進めていて、命令型シナリオよりも、宣言型シナリオのほうが自分達のチームは向いてるよなーという話になったので、シナリオを宣言型に直していこうぜということになりました。

その際に、現在通っているテストは、「Cucumberはstepからstepを呼べるからそれにまとめてしまうぜ」という話になったのでやってみました。

ちなみにCucumberのバージョンは1.2.1です。

まずダメなパターン。

もし /^記事を登録する$/ do
  steps %{
    もし "content"に"記事の内容"と入力する
    かつ "保存する"ボタンをクリックする
    ならば "記事の内容"と表示されていること
  }
end

これでいけると思っていたのですが、エンコードエラーとなってダメでした。
悩んだ挙げ句に、「もし・かつ・ならば」を英語にしたら、通りました。
stepsでまとめるときには、「もし・かつ・ならば」は使えないようです…。

通ったパターン。

もし /^記事を登録する$/ do
  steps %{
    When "content"に"記事の内容"と入力する
    And "保存する"ボタンをクリックする
    Then "記事の内容"と表示されていること
  }
end

まぁ大した変更でもないので現行はこれでまとめていこうと思います。


Kotlinで匿名クラスを使う方法

KotlinでAndroidをしたいと思ってとりあえず手探り状態なのですが、
匿名クラスの宣言方法がよくわからなかったかったので、メモ。

class MyActivity() : Activity() {
  override fun onCreate(savedInstanceState : Bundle?) {
    super.onCreate(savedInstanceState)
    //setContentView(R.layout.main)
    val packageManager = getPackageManager()
    val info = packageManager?.getPackageInfo(getPackageName(), 0)
    val title = "${getString(R.string.app_name)} ${info?.versionName}"
    AlertDialog.Builder(this).setIcon(R.drawable.icon)
      ?.setTitle(title)
      ?.setPositiveButton(R.string.ok, object : DialogInterface.OnClickListener {
        override public fun onClick(dialog : DialogInterface?, which : Int) {
          Toast.makeText(getApplicationContext(), R.string.ok, Toast.LENGTH_SHORT)?.show()
          finish()
        }
      })
      ?.setCancelable(true)
      ?.setOnCancelListener(object : DialogInterface.OnCancelListener{
        override fun onCancel(dialog : DialogInterface?){
          finish()
        }
      })
      ?.create()
      ?.show()
  }
}

object : DialogInterface.OnClickListener {…}という形なんすねー。
そういえばこれはKotlin Advent Calendarで見たわーと思ったら、ちゃんと匿名クラスを書く方法が書いてありますね…。

19日目:キーワード object の威力

今のところ、Kotlinぽい(?)感じの書き方がまだわかってないんですが、引き続きやってみようと思います。


IntellijでAndroidのresフォルダを作る

現在Kotlinで自分のAndroidアプリを作り直してみようかなーと思ってリソースディレクトリをコピペしてから、よし、やるぞ!と思ったら全然R.drawable.iconとかがサジェストされない…。画面はエラーだらけに。画像はあるのに…。

ぐぐったら安定のstackoverflowに。

How can I add drawables to my res folder in intelij IDEA?

どうもresフォルダ上で右クリックし、Android resource directoryを選ぶと。

スクリーンショット 2013-01-31 23.02.43

そして、リソースタイプを選択してディレクトリ名を決めるといいらしい。

スクリーンショット 2013-01-31 23.03.07

たしかに、こうした後にicon.pngをコピペしたらR.drawable.iconを認識するようになりました。
既存のディレクトリはどうしたら認識するようになるのだろうか?全部作り直すのか?