【Kotlin】【Android】RxJavaとUniRxの対応表を作ってみたい 1
はじめに
この記事はRxJava Advent Calendar 2016の2日目に勢いのみでつっこもうとしている記事です。
それはさておき。
先月参加したKansai.kt #2でReactiveProgrammingとRxJavaの話を聞いて以降、本を読みつつコードを書いてみたりしています。
その中で、(お仕事ではUnityを使うことが多く、UniRxも導入しているため)UniRxと同じような処理から書いてみるととっつきやすいんじゃね?と思い立ったため、思いつく順番でそれぞれのコードを書いてみたいと思います。
なおRxJavaの方はAndroid環境で実行しており、言語はKotlinを使います。
環境
- Unity 5.5
IntelliJ IDEA 2016.3
UniRx 5.5
- Kotlin v1.0.5-release-IJ2016.3-2
準備
UniRx
UniRxをインポートしたUnityプロジェクトを作成します。
RxJava
後述しますが、RxJava、RxAndroid、RxBindingを使います(ついでにDataBindingも有効にしています)。
build.gradle
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { compileSdkVersion 25 buildToolsVersion "25.0.0" defaultConfig { applicationId "jp.masanori.kandroidtest" minSdkVersion 19 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main.java.srcDirs += 'src/main/kotlin' } dataBinding { enabled = true } packagingOptions { exclude 'META-INF/rxjava.properties' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.0.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7-kotlin:1.0.0' compile 'io.reactivex.rxjava2:rxjava:2.0.1' testCompile 'junit:junit:4.12' compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" kapt 'com.android.databinding:compiler:1.0-rc5' } repositories { mavenCentral() } kapt { generateStubs = true }
ボタンクリックのイベント
なんとなくGUIから始めます。
ボタンをクリックしたときのイベントを取得してみます。
UniRx
using UnityEngine; using UnityEngine.UI; using UniRx; public class MainCtrl: MonoBehaviour{ public Button startButton; private void Start(){ // ボタンにクリックイベントを追加する. startButton.onClick.AsObservable() .Subscribe(_ => Debug.Log("クリックされました")); } }
RxJava
RxJavaでは上記のようにボタンクリックを取得することはできないようです。
まぁAndroid用に作られたものではないため、当然といえば当然なのですが。。。
ではどうするかといいますと、RxBindingを使用します。
準備のところで書いたように、「compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7-kotlin:1.0.0'」を追加します。
なおJavaで書く場合は「-kotlin」の部分を削除してください。
ここでRxJava2を使っていて、「compile ~」だけを追加した場合に「com.android.builder.packaging.DuplicateFileException」が発生します。
どうもRxJava1系と2系が競合してしまうらしく、下記を追加する必要があります。
~省略~ android{ ~省略~ packagingOptions { exclude 'META-INF/rxjava.properties' } } ~省略~
あとは下記のようにボタンのクリックイベントを取得できるようになります。
import android.databinding.DataBindingUtil import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Log import com.jakewharton.rxbinding.view.RxView import io.reactivex.disposables.CompositeDisposable import jp.masanori.kandroidtest.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { lateinit private var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) // ボタンにクリックイベントを追加する. RxView.clicks(binding.startButton).subscribe { Log.d("RxTest", "クリックされました") } } }
一定時間ごとに処理を行う
次は一定時間ごとに処理を行ってみます。
UniRx
private void Start () { // 500ミリ秒ごとにログ出力. var intervalObservable = Observable.Interval(System.TimeSpan.FromMilliseconds(500d)) .Subscribe(time => Debug.Log("経過: " + time)); // 画面遷移などのタイミングでDisposeを実行して接続を解除する. // intervalObservable.Dispose(); }
RxJava
import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Log import com.jakewharton.rxbinding.view.RxView import rx.Observable import rx.schedulers.Schedulers import java.util.concurrent.TimeUnit class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 500ミリ秒ごとにログ出力. val intervalObservable = Observable.interval(500, TimeUnit.MILLISECONDS, Schedulers.io()) .subscribe { Log.d("RxTest", "経過:" + it) } // 画面遷移などのタイミングで接続を解除する. // intervalObservable.unsubscribe() } }
RxJavaの方ではIDisposableが継承されていないようで、DisposeはできずUnsubscribeするのみとなっています。
処理の書き方自体はかなり近い感じですね。
一定時間後に処理を行う
一定時間が経過したら処理を行います。
UniRx
private void Start () { var timerObservable = Observable.Timer(System.TimeSpan.FromSeconds(3d)) .Subscribe(time => Debug.Log("3秒経過しました")); //timerObservable.Dispose(); }
RxJava
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val timerObservable = Observable.timer(3, TimeUnit.SECONDS) .subscribe { Log.d("RxTest", "3秒経過しました") } // timerObservable.unsubscribe() }
おわりに
細かい違いはともかく、同じものを元にしているだけに大部分の書き方や考え方は共通化されていて助かります。
とりあえずしばらくはこんな感じでバラバラと挙げていって、量が溜まってきたら別途整理、といったところでしょうか。