Architecture Blueprints の非同期処理実装にみる Android SDK の方向性

MVP、MVVM、Clean Architecture、Dagger2、Data Binding、Archtecture Components などいろいろな組み合わせの実装例が ToDoアプリにて公開されています。

googlesamples/android-architecture: A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.

非同期処理部分を見てみると現在はすべて(todo-mvp-rxjavaを除く)が以下の実装となり、非同期処理の主役であった AsyncTask/Loader API を利用した記述は消え去っています。

まず、java.util.concurrent.Executor(s) を使って、AppExecutors を作っておいて、


open class AppExecutors constructor(
    val diskIO: Executor = DiskIOThreadExecutor(),
    val networkIO: Executor = Executors.newFixedThreadPool(THREAD_COUNT),
    val mainThread: Executor = MainThreadExecutor()
) {

  private class MainThreadExecutor : Executor {

    private val mainThreadHandler = Handler(Looper.getMainLooper())

    override fun execute(command: Runnable) {
      mainThreadHandler.post(command)
    }
  }
}

AppExecutors.kt

それに対応するデータベースやストレージ向けのExecutorを作ります。


class DiskIOThreadExecutor : Executor {

  private val diskIO = Executors.newSingleThreadExecutor()

  override fun execute(command: Runnable) { diskIO.execute(command) }
}

DiskIOThreadExecutor.kt

これらを使って以下のようにして非同期処理を実装します。


appExecutors.diskIO.execute {

  // IOスレッドで実行する
  // ...

  appExecutors.mainThread.execute {

    // メインスレッドで実行する
    // ...

  }

}

実装例では、コールバックを使ってPresenterまで伝達しています。


override fun getTasks(callback: TasksDataSource.LoadTasksCallback) {

  appExecutors.diskIO.execute {

    // IOスレッドで実行する
    val tasks = tasksDao.getTasks()

    appExecutors.mainThread.execute {

      // メインスレッドで実行する
      if (tasks.isEmpty()) {
        callback.onDataNotAvailable()
      } else {
        callback.onTasksLoaded(tasks)
      }

    }

  }
}

TasksLocalDataSource.kt

AsyncTask/Loader APIs の排除の方向性は、「Deprecated(廃止予定) samples」に移動されたブランチからも認識できます。

googlesamples/android-architecture: A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.

この流れについては、droidcon NYC 2017 - Android Architecture Round Table でも、話が挙がっていました。

it looks like Google is abandoning old API is like loaders and recommending patterns there are much less coupled with the framework, which is good but what happens with these API is are we abundant in then and I'm talking about classes like sync adapters loader async tasks etc

Google はLoaderのような古いAPI や フレームワークと関係の薄いパターンを推奨することをやめているように見えます。 それはいいことですが、それら古いAPIを捨てることは何を引き起こすか、AsyncAdapter や Loaderなどについて話したいと思います。

今後の、Android SDKは、フレームワークを意識したAPIが増えていくのでしょう。


すばやく理解する「Room x RxJava 」

いい記事があったので。

Room 🔗 RxJava – Google Developers – Medium

まずは、Room で Dao.


@Query(“SELECT * FROM Users WHERE id = :userId”)
User getUserById(String userId);

ここまでで問題なのは、

1. 同期呼び出しでブロッキング。
2. データ変更時に再度呼び出す必要がある。

ということで、RxJava を使いたくなります。

Room は RxJava2.x に対応しています。

Adding Components to your Project | Android Developers

どのように使うのか?

Maybe


@Query(“SELECT * FROM Users WHERE id = :userId”)
Maybe<User> getUserById(String userId);

1. 該当ユーザがなければ、何も返さずに complete。
2. 該当ユーザがあれば、onSuccess となり complete。
3. Maybe が complete されたあとにユーザー情報が更新されても何もしない。

Single


@Query(“SELECT * FROM Users WHERE id = :userId”)
Single<User> getUserById(String userId);

1. 該当ユーザがなければ、何も返さず onError(EmptyResultException)。
2. 該当ユーザがあれば、onSuccess。
3. Single が complete されたあとにユーザー情報が更新されても何もしない。

Flowable


@Query(“SELECT * FROM Users WHERE id = :userId”)
Flowable<User> getUserById(String userId);

1. 該当ユーザはなければ、何も返さず emit もされない。当然、onNext も onError も呼ばれない。
2. ユーザが存在すれば、onNext。
3. ユーザ情報が更新されるたびに、自動で emit されるので、UI上を最新データに更新させることが可能になる。

 

まとめ

これだけ数行でデータベース、非同期処理を簡潔明快に説明できる Room x RxJava の組み合わせ。

おまけに Observable から細分化された RxJava2.x の主役たちの使い方も理解することができます。

素晴らしいですよね。


Java から Kotlin 移行の進捗を「cloc」で確認する

これを確認したかったのです.

特定のディレクトリのファイルやコード行数の確認.

googlesamples/android-architecture at todo-mvp-rxjava

「cloc」てやつを使います.

AlDanial/cloc: cloc counts blank lines, comment lines, and physical lines of source code in many programming languages.

こんな感じで結果表示されます.


for d in ./*/ ; do (cd "$d" && echo "$d" && cloc --vcs git); done

Android プロジェクトの場合, アプリのルートディレクトリでやると,


$ pwd
/Users/maochanz/projects/PlainTemplates
$ cloc .
     674 text files.
     567 unique files.
     140 files ignored.

github.com/AlDanial/cloc v 1.74  T=10.63 s (50.4 files/s, 8239.6 lines/s)
--------------------------------------------------------------------------------
Language                      files          blank        comment           code
--------------------------------------------------------------------------------
JSON                            253              0              0          30758
XML                             223           1749            233          17707
Java                             36             38          24757          10428
Kotlin                           18            245            324            993
Bourne Again Shell                1             19             20            121
DOS Batch                         1             24              2             64
Groovy                            3              8              3             55
Prolog                            1              3              0             18
--------------------------------------------------------------------------------
SUM:                            536           2086          25339          60144
--------------------------------------------------------------------------------

となって,

build ディレクトリもカウントされるので,

src ディレクトリ以下で実行するといいでしょう.


$ pwd
/Users/maochanz/projects/PlainTemplates/app/src
$ cloc .
      77 text files.
      76 unique files.
       1 file ignored.

github.com/AlDanial/cloc v 1.74  T=0.44 s (171.9 files/s, 7442.6 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
XML                             58            177             89           1463
Kotlin                          18            245            324            993
-------------------------------------------------------------------------------
SUM:                            76            422            413           2456
-------------------------------------------------------------------------------

Kotlin による冗長なコードの削減具合もよく分かるはずです.

CLOC -- Count Lines of Code


公式「Android Kotlin Guides」が公開される!! Jake がメンテ中

Kotlinのコードががなんとなく見づらいような気がしてましたが.

こんなの公開されています.

Android Kotlin Guides

このコンテンツについては, GitHubにて公開されていまが,

メンテナーは, Googleにフレームワーク開発において最近合流したあの Jake Warton 神.

android/kotlin-guides: A set of guides for writing Kotlin for Android.

Jake と言えば, ハンガリアン記法についてなどコードスタイルについてはSquare在籍時より強いこだわりを持った発言がありましたよね.

Just Say mNo to Hungarian Notation - Jake Wharton

「Android Kotlin Guides」にはコードスタイルについて記述があります.

例えば, だれもが遭遇していると思われる以下.

When a function signature does not fit on a single line, break each parameter declaration onto its own line. Parameters defined in this format should use a continuation indent (+8). The closing parenthesis ()) and return type are placed on their own line with no additional indent.

関数の記述が一行では収まらないときは, それぞれのパラメータをそれぞれで改行する.それらのパラメータは8のインデントで連続させて, 閉じカッコと戻り型はインデントなしの一行とする.


fun <T> Iterable<T>.joinToString(
        separator: CharSequence = ", ",
        prefix: CharSequence = "",
        postfix: CharSequence = ""
): String {
    // …
}

見やすいですね!

これまで, Square から公開していたように, 定義ファイルで公開してほしいですね!

Android Code Style で インデントはスペース何個?


Play Store の Google 取り分が30%から15%へ 2018年1月から

以前から噂はありました.

2016年6月9日

Recodeが伝えたところによると、Googleもまた新たな利益配分モデルを導入し、月額課金アプリでGoogleが吸い上げる割合を15%に削減する計画があるとのこと。しかもアップルは15%の適用を月額課金アプリの、しかも2年目以降からに限定するのに対して、Googleは1年目からこの利益配分を適用するとしています。

ただ、Recodeはこの新しい利益配分がいつから適用になるのかはまだわからないとしています。

GoogleもAndroidの月額課金アプリ取り分を15%に引き下げるという噂。しかも1年目から対象の可能性 - Engadget 日本版

ついに来年からのようです.

Now, Google is doing the same. Similar to Apple’s approach, an Android developer selling a subscription service will be eligible for the cut so long as the customer in question has been subscribed for more than a year. The company plans to put it into effect starting January 2018.

今回 Googleは同様のことをする予定です。アップルのアプローチと同様に、サブスクリプションサービスを販売しているAndroidデベロッパーは、問題の顧客が1年以上契約している限り、そのカットを受けることができます。同社は、2018年1月から施行する予定です。

Google matches Apple by reducing Play Store fee for Android app subscriptions - The Verge

英語ページでは公式でも追記されています.

Appleと同様に2年目からの定期課金加入者のみのようです.

Note about subscription payments: Starting January 1, 2018, the transaction fee for any subscribers you retain after 12 paid months will be 15% (instead of 30%).

Transaction fees - Play Console Help

なぜか日本語ページではまだ記述がありません.

取引手数料 - Play Console ヘルプ

もしすると, 日本はまだ先になるのかもしれませんが開発者にとってはいい話でしょう.