Gradle ビルド時にやると良い 8つのこと

Gradle のプログレスバーをじっと見てるのは嫌いですよね?

8_things_to_do_while_Gradle_builds_—_Medium

なので, ビルドが完了するまでにできること一覧を作成してみました.

大体, それぞれがいつでもどこでもできる細切れ作業なので, ビルドの間にやるにはちょうどいいと思います.

1. ボキャブラリを増やす.

2. 新しい外国語を学ぶ.

3. Hacker news, Github, ProductHunt, CodePen, StackOverflow, Reddit を徘徊する.

4. 運動をする: 腕立て伏せ, 足首を曲げたり伸ばしたり, スクワットなどたくさんの手軽で器具不要なエクササイズがありますよね.

5. コードを Lint に通す. (3543個も Warning がでたのですぐに止めました)

6. バグを整理する.

7. Android Performance Patterns の動画を見る.

8. Play Store で競合のアプリを見てみる.

あなたはビルドの間, 何をしていますか?

Hacker News Radio (翻訳) - Google Play の Android アプリ
8 things to do while Gradle builds : androiddev
8 things to do while Gradle builds — Medium


苦労した経験から学んだ Androidアプリを作る際の30のこと

Building Android Apps — 30 things that experience made me learn the hard way — Medium

読んでみましたが, 納得できることばかりです.

一読の価値はあると思います.

実際は, 35個ありました.

1. サード・パーティのライブラリを追加する前に2度考えよう. それは本当に重要な決意なのです.

2. ユーザーがそれを見ることができないならば, 描画してはならない.

見えないところは塗りつぶすな – 不要なオーバードロー削除で高速化

3. 本当に必要でなければデータベースは使うな.

4. メソッド数 65000個はすぐに到達するが MultiDex が助けてくれる.

[DEX] Sky’s the limit? No, 65K methods is — Medium

5. AsyncTask のベストな代替は RxJava でこれのほうがかなりよい.

Party tricks with RxJava, RxAndroid & Retrolambda — The Startup — Medium

6. Retrofit がベストなネットワークライブラリである.

Retrofit

7. Retrolambda でコードを短縮しよう.

Retrolambda on Android — Android & Tech — Medium

8. RxJava と Retrofit と Retrolambda を一緒につかうと最強.

Party tricks with RxJava, RxAndroid & Retrolambda — The Startup — Medium

9. EventBus は素晴らしいが, コードが乱雑になるので多用するのは控えている.

greenrobot/EventBus: Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

10. レイヤーでなく機能によって構成する.

ソースディレクトリの構成時にもっておくべき「会社別」のイメージ

11. アプリケーションスレッドのすべてをOFFにしろ.

12. レイアウトとそのヒエラルヒーを最適化するために lint するべし. 削除できる不要なレイアウトを特定できる.

layoutopt | Android Developers

13. Gradle を使っているなら, いろんな方法でスピードアップしよう.

Android お手軽なビルド時間の短縮メモ

14. ビルド時には プロファイルレポートを使え, それぞれのビルドにかかった時間が分かる.

オプションに「–profile」をつけて Run時間が1分から2秒になった話

15. 有名なアーキテクチャーを使え.

Architecting Android…The evolution – Fernando Cejas

16. テストは時間がかかるが, 一度コツを掴むとテストしないときより高速で堅牢となる.

Is Unit Testing worth the effort? - Stack Overflow

17. Dependency Injection を使え. よりモジュール化されテストしやすくなる.

Tasting Dagger 2 on Android – Fernando Cejas

18. Fragmented の podcast を聞け. きっとあなたにとって素晴らしいものとなる.

Fragmented_–_An_Android_Developer_Podcast

Fragmented – An Android Developer Podcast

19. 個人的メールアドレスは Android Market の公開アカウントに使うな.

Google Play - Only one strike is needed to ruin you : Android

20. 常に適切な入力タイプを使え.

Specifying the Input Method Type | Android Developers

21. (Google) Analytics を使って利用パターンを見つけバグを隔離すべし.

22. 新しいライブラリの人気のあるやつを使え. (dryrun を使って出力をより速く)

【AndroidStudio 不要】サンプルアプリは「dryrun」で試してすぐ捨てよう

cesarferreira/dryrun: Try the demo project of any Android Library

23. Service はできるだけ素早く処理して終了しろ.

24. ユーザ名やメールアドレスのサジェストにアカウントマネージャーを使え.

AccountManager | Android Developers

25. ビルドやベータ版の配布や apk の作成にはCIを使え.

26. 自分の CIサーバは使うな. サーバーのメンテに時間を使う. ディスク容量・セキュリテイの問題・SSL攻撃防御のサーバの更新なども. Circle CI や travis, shippabele を使え. これらは 安価で手間も少ない.

27. PlayStore へのデプロイは自動化しよう.

Triple-T/gradle-play-publisher: Gradle Plugin to upload your APK and metadata to the Google Play Store

28. ライブラリが巨大でその一部しか使ってない場合は, より小さくなる方法を探せ(例えば プロガードを利用する)

Shrink Your Code and Resources | Android Developers

29. 実際に必要以上なモジュールを使うな. もしそのモジュールを頻繁に更新していないのなら, コードからそれらをコンパイルする時間や, 以前のそれぞれのモジュールのビルドが最新版であるかチェックも必要となることについて考えることが重要です. バイナリ .jar/.aar の簡単な読込みにすると4倍くらい向上できます.

30. PNGを捨ててSVG化することを考え始めよう.

Vector Asset Studio | Android Developers

31. ライブラリの抽象化クラスを作れ. ライブラリを変更するときに一箇所の変更で簡単に行うことができる.

JakeWharton/timber: A logger with a small, extensible API which provides utility on top of Android's normal Log class.

32. Connectivity とその種類を監視しろ. (WiFi のときにより多くのデータを更新しているか?)

33. 電源とバッテリーを監視しろ. (充電中に更新データを多くしているか, バッテリーが少ないときには更新を停止しているか?)

34. UIとはジョークのようなものだ. 説明が必要であればそれは良くない.

35. テストのパフォーマンスは偉大です. テストで何も壊れないか確認し、その後ゆっくりと正しい実装を記述する → 最適化

Dan LewさんはTwitterを使っています: "Tests are great for performance: Write slow (but correct) implementation then verify optimizations don't break anything with tests."

しかし, Medium ていい記事ばかりあるけどなぜなのかな.


ゲージ付の折れ線グラフをすばやくつくれるライブラリ「Spark」

折れ線グラフをすばやくつくりましょう.

Introducing_Spark_—_Robinhood_Engineering_—_Medium

Introducing Spark — Robinhood Engineering — Medium

手順

1. ライブラリを追加する.


compile ‘com.robinhood.spark:spark:{latest release}’

2. View を設置する.


<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.robinhood.spark.SparkView
        android:id="@+id/sparkview"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:spark_lineColor="@color/colorAccent"
        app:spark_scrubEnabled="true"
        app:spark_animateChanges="true"/>
...

3. データ float[] を渡す Adapter を作る.


public class MyAdapter extends SparkAdapter {
    private float[] yData;

    public MyAdapter(float[] yData) {
      this.yData = yData;
    }

    @Override
    public int getCount() {
      return yData.length;
    }

    @Override
    public Object getItem(int index) {
      return yData[index];
    }

    @Override
    public float getY(int index) {
      return yData[index];
    }
}

4. Adapter を View にセットして, ゲージをタッチしたときの Listener をつける.


SparkView sparkView = (SparkView) findViewById(R.id.sparkview);
sparkView.setAdapter(new MyAdapter(data));
sparkView.setScrubListener(new SparkView.OnScrubListener() {
    @Override
    public void onScrubbed(Object value) {
        if (value == null) {
            scrubInfoTextView.setText(R.string.scrub_empty);
        } else {
            scrubInfoTextView.setText(getString(R.string.scrub_format, value));
        }
    }
});

5. 出来上がり

20160419-072257_1

数値の推移を確認するには折れ線グラフは非常にわかりやすく, タップしてその時点の数値も簡単に表示できてしまうこのライブラリは非常に重宝するものだと思われます.

robinhoodmarkets/spark: A simple Android sparkline chart view.


CoordinatorLayout がわかりづらいのは デフォルト のせい?

よくある画面要素の組み合わせ ActionBar + RecyclerView + FAB.

ActionBar 部分をスクロール時に上にスライドさせて消したいですよね!

まずは CoordinatorLayout で囲みます.

レイアウトはこんなかんじの構成ですね.


<CoordinatorLayout>
  <AppBarLayout>
    <Toolbar />
  </AppBarLayout>
  <RecyclerView />
  <FloatingActionButton />  
</CoordinatorLayout>

ここでは, 連携する挙動の始まりとなる「きっかけ」を RecyclerView のスクロールとしましたが, 以下の View や Layout は, デフォルトで同様に「きっかけ」にすることができます.

HorizontalGridView
NestedScrollView
RecyclerView
SwipeRefreshLayout
VerticalGridView

NestedScrollingChild | Android Developers

よく画面をみてみると, RecyclerView の最上段をみることができないようになってますね!

20160414-190459_1

それは, CoordinatorLayout は FrameLayout だからです.

CoordinatorLayout is a super-powered FrameLayout.

CoordinatorLayout | Android Developers

でも, とりあえず無視します.

次に, アクションバー部分が「きっかけ」に反応して「ふるまう」するようにします.

AppBarLayout または Toolbar に, 属性「app:layout_behavior」をつけて, 「ふるまう」時の挙動を追加したくなります.

でも, 必要なかったりします.

ふるまいを記述する Behavior は, デフォルトですで に AppBarLayout にアノテーションを利用してセットされているからです.


@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {

Cross Reference: AppBarLayout.java

なので, ふるまい方の種類だけをその子である Toolbar 記述します.


<CoordinatorLayout>
  <AppBarLayout>
    <Toolbar
      app:layout_scrollFlags="scroll|enterAlways" />
  </AppBarLayout>
  <RecyclerView />
  <FLoatingActionButton />  
</CoordinatorLayout>

ここで, 動かしてみます.

20160414-191401_1

アクションバーが消えていくようになりましたね!

最後に, RecyclerView 自体も「ふるまわ」せます.

AppBarLayout のふるまい方と同じふるまい方をするように同じ Behavior をセットします.


<CoordinatorLayout>
  <AppBarLayout>
    <Toolbar
      app:layout_scrollFlags="scroll|enterAlways" />
  </AppBarLayout>
  <RecyclerView
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />
  <FLoatingActionButton />  
</CoordinatorLayout>

ここでいきなり現れた文字列 @string/appbar_scrolling_view_behavior は, デフォルトでセットされている


android.support.design.widget.AppBarLayout$ScrollingViewBehavior

のことです.

AppBarLayout にデフォルトで設定されているものと同じですね.

ここで, また動かしてみます.

20160414-195431_1

AppBarLayout の Behavior と同じものを RecyvlerView にもセットしたので, 同じように動きます.

スクロール時にAppBarと同じように開閉スライドすることになるので, RecyclerView との重なり合いがなくなり RecyclerView の最上段も表示されるようになりましたね!

実際の簡略化していないレイアウトを貼っておきます.


<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
  <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:title="@string/app_name"
        app:layout_scrollFlags="scroll|enterAlways" />
  </android.support.design.widget.AppBarLayout>
  <android.support.v7.widget.RecyclerView
      android:id="@+id/recycler_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_behavior="@string/appbar_scrolling_view_behavior" />
  <android.support.design.widget.FloatingActionButton
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginRight="16dp"
      android:layout_marginBottom="16dp"
      android:layout_gravity="right|bottom"
      android:src="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>

以上のように, レイアウトファイルだけを編集するだけで, インタラクティブな挙動を画面の要素たちに行わせることができるので, 便利な気もしますね!!

→ 少しややこしいので「まとめ」ようとしてつづく (作成中)


直感的に理解する RxJava その2: Operator

ReactiveX

その1では, RxJava の基本的な構造と map() オペレータの紹介をしました. しかし, これだけではまだまだ実際には利用できません.

しかし, RxJava の実力の大部分はオペレータなので, すぐに利用できるようになることができます.

サンプルをみながらさらに Operator を学んでいきまよう.

設定

利用可能なこのメソッドがあるとします.


// テキスト検索からWEBサイトのURLの List を返す
Observable<List<String>> query(String text); 

テキストで検索してこれらの結果を表示したいとします. 前回の記事をふまえて考えると以下のようなものが思いつくかもしれません.


query("Hello, world!")
    .subscribe(urls -> {
        for (String url : urls) {
            System.out.println(url);
        }
    });

これは少し残念です. なぜなら, データストリームの変換を利用していません. もし, それぞれのURLを変形したい場合はすべてを Subscriber の中でやらなければなりません. 便利な map() を利用していません.

urls -> urls 内で map() を作成することもできますが, 残念ながら, その後のすべての map() の呼び出しのたびに for-each ループを持つことになります.

この方法ではどうか

Observable.from() はアイテムのコレクションを取得し, それぞれを一度に発することができます.


Observable.from("url1", "url2", "url3")
    .subscribe(url -> System.out.println(url));

こんな感じで使えます.


query("Hello, world!")
    .subscribe(urls -> {
        Observable.from(urls)
            .subscribe(url -> System.out.println(url));
    });

for-each ループをなくすことはできますが, 結果, コードはややこしくなり入れ子した Subscription になってしまいます. しかも変更しづらく, 実は RxJava の重要な機能を壊しています.

良い方法

ここで flatMap() の登場です.

Observable.flatMap() は Observable から 別の Observable を作成します. アイテムからストリームを作成し別の Observable とすることができます.


query("Hello, world!")
    .flatMap(new Func1<List<String>, Observable<String>>() {
        @Override
        public Observable<String> call(List<String> urls) {
            return Observable.from(urls);
        }
    })
    .subscribe(url -> System.out.println(url));

何が起こっているかわかりやすく書いていますが, ラムダ式で簡単にできますね.


query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .subscribe(url -> System.out.println(url));

ここで大事なことは「返された新しい Observable は Subscriber が利用するもの」ということです. それは, 連続した Observable.from() から返された独立した String たちです.

さらにより良く

flatMap() で欲しい Observable を返すことができましたがまだ十分ではありません.

2つ目の次のメソッドを可能にしなければならないと仮定します.


// サイトのタイトルを返す(もし404なら null を返す)
Observable<String> getTitle(String URL);

URLを表示する代わりに, そのページのタイトルを表示したい場合には問題が有りそうです. メソッドはそれぞれのURLに対してのみ動作して, String ではなくObservable を返します.

しかし, それも flatMap() で簡単に解決できます. Subscriber に到達する前にURLリストが個別のアイテムに分割された後は flatMap() の中でそれぞれの URLに対して getTitle() を使うことができます. .


query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(new Func1<String, Observable<String>>() {
        @Override
        public Observable<String> call(String url) {
            return getTitle(url);
        }
    })
    .subscribe(title -> System.out.println(title));

そしてさらにラムダ式でシンプルにします.


query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(url -> getTitle(url))
    .subscribe(title -> System.out.println(title));

複数のメソッドと Observable の返却を同時に組み合わせて行うことができます. すばらしいですね.

それだけでなく, どのように2つのAPIコールを組み合わせてひとつのチェインにいれたか, に注意してみてください. いくつでもAPIコールをいれることができます. 知ってますよね. APIコールの同期を保持して, コールバックを連携させて, データを取得することがどれだけ面倒か. これはすでに, コールバック地獄をスキップしています. そして同じロジックの中にまとめて短いリアクティブなコールになっています.

Oprerator の豊富さ

ここまでで2つの Operator しか使っていませんが, もっとたくさんあります. 他のものを使うとどれだけコードを改善できるでしょう?

URLが 404 のとき getTitle() は null を返します. "null" は表示させたくありませんね. 変更してそれらをフィルタしましょう.


query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(url -> getTitle(url))
    .filter(title -> title != null)
    .subscribe(title -> System.out.println(title));

fileter() は boolean のチェックを通過したもののみ発します.

そして, 今度は, 5個までの結果だけ表示しましょう.


query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(url -> getTitle(url))
    .filter(title -> title != null)
    .take(5)
    .subscribe(title -> System.out.println(title));

take() は, 設定された数字を最大の個数として発します.

今度は, それぞれのタイトルを保存しましょう.


query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(url -> getTitle(url))
    .filter(title -> title != null)
    .take(5)
    .doOnNext(title -> saveTitle(title))
    .subscribe(title -> System.out.println(title));

doOnNext() は, 追加したいふるまいをそれぞれのアイテムが発せられると同時に行います. この場合はタイトルを保存しています.

ここまで, ストリームデータをどれだけ簡単に操作できるかみてきました. 材料をあなたのレシピの合わせて混乱することなく何度も処理できますね.

RxJava には, 大量の Operator がありますが 何ができるか参照してみる価値はあると思います.
習得するのに時間がかかるかもしれませんが, 習得するとすぐに使えて役に立つと思います.

カスタムオペレータでさえ書くことができます. この記事では書きませんが, 基本あなたがやりたいと思えばできることでしょう.

それがどうしたの?

なぜ これらの operator を使うのか?

3: 「Operator は データストリームに対してどんな操作でもできる.」

限度となるのはあなた自身です.

シンプルな Operator のチェインで複雑なロジックを設定することができ, 構成したままの状態でコードを小分けに分割します。

それに加えて, 利用するために変換されたデータはどれだけシンプルになっているか考えてみてください. 最後のサンプルのコードでは, 2つのAPIをコールして, データを操作し, それをディスクに保存しました. しかし, Subscriber は それが利用するシンプルな Observable しか知りません. 「カプセル化」によりコーディングをより簡単にすることができます.

次回, その3ではRxJavaの他の素晴らしい機能であるエラーハンドリングと並行処理についてです.

[原文] Grokking RxJava, Part 2: Operator, Operator

直感的に理解する RxJava その1: 基本的な構成

直感的に理解する RxJava その3: リアクティブであることのメリット

直感的に理解する RxJava その4: Reactive Android