くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

jdeferred+RetrolambdaでAndroidの非同期処理をシンプルに!

非同期処理はAsyncTaskLoaderを使ってたけど、だんだんめんどくさくなってきた。。。

非同期処理をいい感じに扱ってくれるライブラリjdeferred

AndroidでもJava8のラムダ式を使えるようにするライブラリRetrolambda

を使うとシンプルにかけるらしいので、その備忘録

qiita.com qiita.com

非同期処理のライブラリはAndroid-promiseとかRxAndroidとかあるけど、

jdeferredのほうがよさ気な気がしてるけど違いはよくわかってない笑

環境は以下の通り

Retrolambdaの導入

Java8をインストール

Java8をインストールして環境変数にパスを設定する

$ javac -version
javac 1.8.0_45

build.gradleにRetrolambdaとjdeferredを追加

AndroidがJava8に対応していないため、Gradleでコンパイルをするとエラーになってしまう

それを回避するために、retrolambda用のgradleのプラグイン(gradle-retrolambda)がある

なので、プラグインを使えるようにブロジェクトのbuild.gradleに

classpath 'me.tatarka:gradle-retrolambda:3.2.2'を追加

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.0'
        classpath 'me.tatarka:gradle-retrolambda:3.2.2'
    }
}

また、アプリケーションモジュールのbuild.gradleに

  1. apply plugin: 'me.tatarka.retrolambda'を追記してプラグインを有効にし
  2. compileOptionsにJavaVersion.VERSION_1_8を追記して、
    Java8でコンパイルするようにし、
  3. dependenciesにorg.jdeferred:jdeferred-android-aar:1.2.4を追記して、
    jdeferredを使えるようにします
    • apklib版のjdeferred-androidもあるけど、gradleはaar形式のみ対応

全体としては以下な感じ

apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'

android {
 compileSdkVersion 20
    buildToolsVersion '22.0.1'

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 20

        ・・・
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    compile project(":app")'
    compile 'org.jdeferred:jdeferred-android-aar:1.2.4'
}

jdeferredを使う

Java上で書くときは以下の感じ。メソッドチェーンでいい感じに書けます

AndroidDeferredManager dm = new AndroidDeferredManager();
dm.when(() -> {
  return //非同期の処理
}).done(result -> {
  //非同期処理が成功した時の処理
}).fail(tr -> {
  //非同期処理が失敗した時の処理
});

ほかにも、非同期処理を連結するthen()や、成功失敗にかかわらず実行される処理always()なんてのもあります!

AndroidDeferredManager dm = new AndroidDeferredManager();
dm.when(() -> {
  return //非同期の処理 その1
}).then(result -> {
  return //非同期の処理 その2
}).then(result2 -> {
  return //非同期の処理 その3
}).done(result3 -> {
  //非同期処理が成功した時の処理
}).fail(throwable -> {
  //非同期処理が失敗した時の処理
}).always((state, resolved, rejected) -> {
  //成功失敗に関わらず行う処理
});

なんてスマートなんでしょう!!

以上!!