volley(サブプロジェクト)のbuildToolsVersionをafterEvaluateで上書く
Android StudioがBetaになったので、0.8.2に上げようとしたらモジュールのビルドでハマった。
Android Studioのバージョンを上げるときは、build.gradleを弄る時でもある。 Betaに上げるからには最新版のGradleプラグインとAndroid SDKでコンパイル&ビルドできるようにしたい。
// project/gradle/gradle-wrapper.properties distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip // project/build.gradle buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.12.+' } } // project/app/build.gradle android { compileSdkVersion 20 buildToolsVersion '20.0.0' }
しかしビルドエラー。
ルートプロジェクトのGradleプラグインのバージョンを0.12に上げると、buildToolsVersionが"19.1"以上でないとビルドできない。
僕の環境ではvolleyをモジュール(submodule)として組み込んでいて、compileSdkVersionとbuildToolsVersionがこのように指定されている。
// modules/volley/build.gradle android { compileSdkVersion 19 buildToolsVersion = 19 }
volleyのソースを見る限りbuildToolsVersionを20に上げても特に問題なさそうなので、何とかしてビルドが実行される前にandroid()の中身を上書きしたい。
と思って、Gradle User Guideを眺めていたら、Project.afterEvaluate()というものを見つけた。
Project.afterEvaluate()は、そのプロジェクトのビルドスクリプトが評価された後に実行されるらしい。まさにやりたいことと一致!
Gradleで分からないことがあれば、Gradle User Guideを見るのがオススメ。 Gradleのバージョンごとに用意されているので、使っているものに合わせて見るとよさげ(ちょくちょく変わったりするので)。
subprojects { subproject -> afterEvaluate { if (subproject.plugins.hasPlugin('android-library')) { android { compileSdkVersion 20 buildToolsVersion '20.0.0' } } } }
これで、モジュールとして組み込んでいるライブラリプロジェクト全てのcompileSdkVersionとbuildToolsVersionをアプリのそれと合わせることができる。
もし特定のプロジェクトだけどうしても"19.1"でビルドしたければ、プロジェクトごとに指定すればおk。
project(':modules:volley') { afterEvaluate { android { compileSdkVersion 20 buildToolsVersion '19.1' } } }
Android meets RxJava
少し、いやかなり前に渋谷Javaで「Android meets RxJava」というタイトルでLTしてきました。 スライド上げるのが遅くなってすいません。。。
freeeのAndroidアプリの開発前にチーム内で考えていたのが、テストの書きやすさを考慮するとどうしてもFragmentとAPIのやりとり含むビジネスロジックを切り分けたいというところで、 ViewController/ViewModel/Modelを上手く疎に分けられる仕組みが必要でした。
先行して開発していたiPhone版では、ReactiveCocoaを導入して上手くいったこともあり、FRPが出来るJavaのいいライブラリはないか探していたところ、上手くマッチしそうだったのがRxJavaでした。
RxJavaのObservable、Subscriber、Func/Actionを使うことで、API呼び出し/モデルへの変換/画面への表示を上手く切り分けることが可能になります。
また、ViewModelのプロパティをFragmentからバインディングすることにより、データの状態をFragment側で管理する必要がなくなります。
Fragment側でデータの状態を持ってしまうと、いざそのテストを書く際にUIが必要になるので非常にめんどくさい。ViewModelまでで完結できればユニットテストだけでOK。 とはいえ、スライドにも書いてますが、ビジネスロジックがそこまで複雑でなければEventBusなどでやり取りするのもアリだと思います。
こういうFRPなライブラリをクライアントアプリで使うと、コアな部分で使うためどうしてもロックインを防げないのがデメリットです。 Reactive Streamsによる標準化に期待。