GroovyとRxJavaとRxAndroid、シンプルなサンプルを作ってみた

# はじめに

　@rejuspotaroさんの[関数型言語を学ぶことは実務でどう役に立ったか](http://rejasupotaro.github.io/2014/05/11/47.html)を見てRxJavaを使ってみたくなりました。また、[iOSのSwiftとAndroidのGroovy](http://rejasupotaro.github.io/2014/06/05/49.html)を見て、RxJavaをAndroidで使うなら、Groovyでだなと思いました。

　また、上記の記事では、言及されていませんでしたがRxAndroidというものがあるようです。Viewのクリックのストリームや、EditTextの変更のストリームを生成するメソッドが用意されているみたいです。

　今まで私は、RxJavaをちょっと試してみるならGroovy([これ](http://qiita.com/RyotaMurohoshi/items/99475255e56f8fae712b)と[これ](http://qiita.com/RyotaMurohoshi/items/2a30a74c0074e11d0207))とか、[RxGroovyについて](http://qiita.com/RyotaMurohoshi/items/3f1f3cde0e5c6785b2f1)投稿していましたが、今回やっとRxAndroid、RxJavaをGroovyで使ってみたいと思います。


# ボタンクリック回数を表示
![click_count.png](https://qiita-image-store.s3.amazonaws.com/0/4125/03d00591-c757-c7c0-3a6f-fa5fbe337792.png "click_count.png")

　ボタンクリックの回数をTextViewに表示したいと思います。(ええ、分かっていますよ。Rx使う必要ないシンプルすぎる例ですね。)

```xml:ボタンクリック回数を表示用のレイアウト
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text_view"
        android:layout_centerInParent="true"
        android:text="0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button"
        android:layout_centerHorizontal="true"
        android:text="click"
        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

```

　rx.android.observables.ViewObservableクラスのclicksメソッドを使います。引数に渡したViewのクリックストリームを作ります。(@rejuspotaroさんの記事で紹介していたサンプルでは、このViewObservable#clicks該当するメソッドを@rejuspotaroさんが自作されていました。)

　Javaでまず使ってみます。(Retrolambdaは使っていないです。)

```java:ボタンクリック回数を表示(java)
package com.mrstar.rx_anroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import rx.android.events.OnClickEvent;
import rx.android.observables.ViewObservable;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.functions.Func2;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewObservable.clicks(findViewById(R.id.button))
            .map(new Func1<OnClickEvent, Integer>() {
                @Override
                public Integer call(OnClickEvent clickEvent) {
                    return 1;
                }
            })
            .scan(new Func2<Integer, Integer, Integer>() {
                @Override
                public Integer call(Integer acc, Integer current) {
                    return acc + current;
                }
            })
            .subscribe(new Action1<Integer>() {
                @Override
                public void call(Integer clickCount) {
                    TextView textView = (TextView)findViewById(R.id.text_view);
                    textView.setText(clickCount.toString());
                }
            });
    }
}
```

　インターフェースを実装した匿名クラスのインスタンスを作るところが、かなり冗長ですね。(Retrolambdaを使えばいいのでしょうが。)

　次にGroovyで書いてみます。

```groovy:ボタンクリック回数を表示(groovy)
package com.mrstar.rx_anroid

import android.app.Activity
import android.os.Bundle
import rx.android.observables.ViewObservable

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewObservable.clicks(findViewById(R.id.button))
            .map { 1 }
            .scan { acc, current -> acc + current }
            .subscribe {
                findViewById(R.id.text_view).setText(it.toString())
            }
    }
}
```

　すっきり！

# EditText内の文字数を入力するたび更新し表示
![edit_text_length.png](https://qiita-image-store.s3.amazonaws.com/0/4125/f5163c0c-bf87-98dd-ba40-499e0bef1df5.png "edit_text_length.png")

　EditText内に入力した文字の文字数を、TextViewに表示しようと思います。EditText内の文字列が更新されたら、TextViewの文字数も更新されます。(はい、これも別にRx使う必要は無いくらいシンプルですね。)

```xml:テキスト文字数表示用のレイアウト
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text_view"
        android:layout_centerInParent="true"
        android:text="0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/edit_text"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>
```

　今度はrx.android.observables.ViewObservableクラスのtextメソッドを使います。これの返り値は、Observable\<String\>ではなくて、Observable\<OnTextChangeEvent\>です。


```java:テキストの文字数を表示(Java)
package com.mrstar.rx_anroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import rx.android.events.OnTextChangeEvent;
import rx.android.observables.ViewObservable;
import rx.functions.Action1;
import rx.functions.Func1;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewObservable.text((TextView)findViewById(R.id.edit_text))
            .map(new Func1<OnTextChangeEvent, Integer>() {
                @Override
                public Integer call(OnTextChangeEvent onTextChangeEvent) {
                    return onTextChangeEvent.text.length();
                }
            })
            .subscribe(new Action1<Integer>() {
                @Override
                public void call(Integer textLength) {
                    TextView textView = (TextView)findViewById(R.id.text_view);
                    textView.setText(textLength.toString());
                }
            });
    }
}

```

　こちらもGroovyで書き換えます。

```groovy:
package com.mrstar.rx_anroid

import android.app.Activity
import android.os.Bundle

import rx.android.observables.ViewObservable

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewObservable.text(findViewById(R.id.edit_text))
            .map{ it.text.length() }
            .subscribe{
                    findViewById(R.id.text_view).setText(it.toString())
            }
    }
}
```

　これまた、すっきり。

# まとめ
　非常に簡単な例ですが、RxJava・RxAndroidそしてGroovyを使ってみました。

　もっと複雑なコードにもチャレンジしてみたいです。

# 良かったら、これもどうぞ！

* [Javaのライブラリをチョロっと試すなら、Groovyで試すといいと思うんです！](http://qiita.com/RyotaMurohoshi/items/99475255e56f8fae712b)
* [GroovyOnAndroidやRxJavaをやりたい人のための、Groovyのクロージャの書き方・使い方メモ](http://qiita.com/RyotaMurohoshi/items/2a30a74c0074e11d0207)
* [RxJavaをGroovyで使う。そしてRxGroovyがやっていること(ExtensionModule)](http://qiita.com/RyotaMurohoshi/items/3f1f3cde0e5c6785b2f1)
* [AndroidStudio0.6.1とGroovy2.4-beta-1で、とりあえずGroovyでAndroidアプリを作ってみた。](http://qiita.com/RyotaMurohoshi/items/4e11acc347dbd766e913)
* [【Unityでも】UniRxを使ってみた。マウスクリックの回数を数える【リアクティブプログラミング】](http://qiita.com/RyotaMurohoshi/items/7e1509e03d8e3a1eae4f)


# app/build.gradle
```gradle:app/build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.12.2'
        classpath 'me.champeau.gradle:gradle-groovy-android-plugin:0.2.+'
    }
}

apply plugin: 'com.android.application'

android {
    compileSdkVersion 20
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "com.mrstar.rx_anroid"
        minSdkVersion 15
        targetSdkVersion 20
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    packagingOptions {
        // workaround for http://stackoverflow.com/questions/20673625/android-gradle-plugin-0-7-0-duplicate-files-during-packaging-of-apk
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/groovy-release-info.properties'
    }
}

apply plugin: 'me.champeau.gradle.groovy-android'

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'io.reactivex:rxandroid:0.22.0'
    compile 'org.codehaus.groovy:groovy:2.4.0-beta-3:grooid'
    compile ('org.codehaus.groovy:groovy-json:2.4.0-beta-3') {
        transitive = false
    }
}

repositories {
    jcenter()
}
```