これは スピカ Advent Calendar 2015 の22日目の投稿です。(といいつつ、投稿が遅れてすみせん..)
私は Android版ネイルブック の開発に携わっています。ネイルブックでは iOS版 と合わせて 毎日2000枚以上 もの新しいネイル画像が投稿され、累計で投稿されたネイル画像は 100万枚 を超えます。
Android 版については、つい先日(12/25)にバージョン 2.0.0
がリリースされました(上のキャプチャは少し古いバージョンのものですが)。このバージョンアップでデザイン&操作性ともに大きく向上し、画像閲覧系アプリとして良い参考になるかと思います。是非ダウンロードして試していただければ。
今回は Android版ネイルブック で利用しているライブラリの中から、便利に使っているものを厳選して10個、紹介したいと思います!
① Picasso
ネイル画像はサーバ側からは Amazon CloudFront で配信し、アプリからの読み込みには Picasso を利用しています。
dependencies {
compile 'com.squareup.picasso:picasso:2.5.2'
}
Picasso を利用する場合は、あわせて OkHttp を導入しておくと、特に何も設定せずともネットワーク接続に OkHttp を利用してくれるようになります。
dependencies {
compile 'com.squareup.okhttp:okhttp:2.5.0'
}
基本的な使い方は Picasso のサイトを見てたりググッてもらえれば分かると思います。ネイルブックでは画像を読み込み終わったら◯◯する、という処理がわりとあるのですが、次のようなコールバックも簡単に書けて便利です。
Picasso.with(someImageView.getContext().getApplicationContext())
.load(image_url_string)
.placeholder(R.drawable.loading_image)
.error(R.drawable.error_image)
.into(someImageView, new Callback() {
@Override
public void onSuccess() {
// 画像を読み込み終わった時に実行する処理
}
@Override
public void onError() {
// エラーの時に実行する処理
}
});
Transformation で画像の加工もできます。例えば 画像を円でくり抜くTransformation があるとしたら、次のように利用します。
Picasso.with(someImageView.getContext().getApplicationContext())
.load(image_url_string)
+ .transform(new CircleTransformation()) // 円でくり抜く
.placeholder(R.drawable.loading_image)
.error(R.drawable.error_image)
.into(someImageView);
Transformation は独自で作成する他に、私はまだ利用したことが無いのですが wasabeef さんが開発されている Picasso Transformations などがあります。
また Picasso のは読み込んだ画像がネットワークから新たに読み込まれたのか / データストアのキャッシュからなのか / メモリからなのかを、画像の左上に赤 / 青 / 緑 のマークをつけて教えてくれる機能(インジケータ表示)があります。
利用するには Application クラス等で次のようにします。
public class SomeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Picasso.with(getApplicationContext()).setIndicatorsEnabled(true);
}
}
}
次のように Picasso が利用するメモリの容量(デフォルトでは端末で利用できる容量の約15%)を変更することも出来ます。
② Stetho
SharedPreferences
の中身を Chrome Developer Tools で確認するのに利用しています。
dependencies {
debugCompile 'com.facebook.stetho:stetho:1.2.0'
}
ネイルブックでは debug ビルド時のみしかバイナリに組み込まれないよう
debugCompile
で定義しています。
利用するには Application クラス等で次のように初期化するだけです。
public class SomeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Stetho.initializeWithDefaults(this);
}
}
ネイルブックでは relese / debug ビルドで Application クラスのソースを分けています。もし分けないなら
build.gradle
のcompile
で Stetho を読み込み、BuildConfig.DEBUG == true
の場合に Stetho を初期化する、とすると debug ビルド時のみ Stetho が有効となる状態が作れます。
上記のように初期化しておくと、Chrome Developer Tools で inspect できるようになります。
次のように SharedPreferences
の中身が確認できます。(あまり見せれないのでモザイクかけてますが..)
ネイルブックでは画像の読み込みに、先に紹介した Picasso(とOkHttp) を利用しているのですが、Stetho-OkHttp を導入することにより、画像のHTTPリクエストも Chrome Developer Tools で確認できるようになります。
dependencies {
debugCompile 'com.facebook.stetho:stetho-okhttp:1.2.0'
}
public class SomeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Stetho.initializeWithDefaults(this);
OkHttpClient client = new OkHttpClient();
client.networkInterceptors().add(new StethoInterceptor());
Picasso picasso = new Picasso.Builder(this).downloader(new OkHttpDownloader(client)).build();
Picasso.setSingletonInstance(picasso);
}
}
ただ、読み込む画像が多いとアプリの動作がかなり重くなります。
また、まだ試したことはないのですが Stetho-Realm を導入すると、Realm のデータの中身を Chrome Developer Tools で確認できるようになるようです。
③ EventBus
いわゆる pub/sub で任意のインスタンスにイベントを通知することができます。
dependencies {
compile 'de.greenrobot:eventbus:2.4.0'
}
イベントを送るには適当なイベント用のクラスを作り、post
メソッドで投げるだけです。
イベントを受け取る側は
EventBus.getDefault().register(<イベントを受けるインスタンス>)
としておいて EventBus 全体のイベントを購読しておく必要があります。
イベント用のクラスは普通の Java のクラスです。
イベント用のクラスは通知を送る側のクラス、もしくは、通知を受ける側のクラスのインナークラスと定義しておくと、コード上わかりやすいです(1対多もしくは多対1のうち"1"の方)。<クラス名>.<イベント用クラス名> となるのでそのイベントがどのクラスから送られる/どのクラスへ送られるかが明確になるためです。
ただ EventBus を多用すると処理の繋がりが分かりにくくなるので、どうしてもコールバックの引き回しが難しい(コードが煩雑になる)ところに限定して利用するのがよいと思います。
ネイルブックでは、一覧画面から詳細画面を開き(別Activity)、詳細画面で行った操作を一覧画面にも反映する、という箇所で EventBus を利用しています。
その他の使いどころとしてよくありそうなのは、ListView の Adapter や ViewHolder で起きたイベント(例えば ListView の各行にあるボタンのクリック等)を Adapter 利用元の Activity/Fragment へ通知するようなシチュエーションでしょうか。
最近は、RxJava で同様なことができるのかもしれません。
④ Butter Knife
View のインジェクト(レイアウトXMLファイル上の View の id と Activity/Fragment 上のインスタンス変数の対応づけ)で利用しています。
dependencies {
compile 'com.jakewharton:butterknife:7.0.1'
}
findViewById
の記述を無くせたり、クリックイベント等を簡潔に書けたりします。あわせて android-apt を導入しておくと、Butter Knife で生成されたコードが Android Studio から閲覧できます。
Android Studio 用のプラグインを導入しておくと更に捗ります。こちらの投稿で紹介しました。
また、ネイルブックでは単なる View のインジェクトだけでなく、所謂 MVC でいう Controller への View のインジェクトで利用しています。この方法については、アドベントカレンダーの15日めに詳しく書いたので、宜しければご覧ください。
⑤ LeakCanary
リークの検出で利用しています。
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
}
ネイルブックでは debug ビルド時でしか組み込まれないよう
debugCompile
で定義しています。
利用するには Application クラス等で次のように初期化するだけです。
public class SomeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
ネイルブックでは relese / debug ビルドで Application クラスのソースを分けています。
この状態でアプリを起動すると、端末に LeakCanary アプリが自動でインストールされ、
リークを検出すると画面上にトーストで表示してくれます。LeakCanary アプリ上でリークの履歴を閲覧することも可能です。
⑥ Timber
デバッグ用のログ出力で利用しています。
dependencies {
compile 'com.jakewharton.timber:timber:3.1.0'
}
最新バージョンは執筆時点で
4.1.0
ですが、minSdkVersion
の関係でネイルブックでは3.1.0
を使っています。
利用するには Application クラス等で次のように Tree
というものを設定します。
public class SomeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
}
}
この
Tree
をカスタマイズすることにより、ログ出力を色々できるのですが、ここでは割愛します。ネイルブックでは標準で用意されているDebugTree
を設定しています。
単純なログ出力は次のように書けます。
Timber.tag("hoge").i("piyo=%s", "fuga");
%s %d 等で置き換えが出来る。
不要なログ出力が残ってしまう(コードの消し忘れ)問題に対しても有用です。こちらに書きました。
⑦ Crashlytics (Fabric)
クラッシュログの収集、および、開発版 Android アプリの社内配布で利用しています。
Crashlytics を利用するには、合わせて Android Studio 用のプラグインを導入します。こちらの投稿で紹介しました。
上記 プラグインを利用することにより自動で Gradle 用のファイルが修正されるので簡単にプロジェクトへ導入することが出来ます。
Crashlytics の初期化は次のように Application クラスで実施しておくのが良いかと思います。
public class SomeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
}
}
⑧ Google Analytics
サイト:https://www.google.co.jp/intl/ja_ALL/analytics/index.html
画面の表示回数やタップイベント回数、プッシュ通知の開封数等の計測で利用しています。グロースハックでは必須です。
dependencies {
compile 'com.google.android.gms:play-services-analytics:8.3.0'
}
ちなみにプロジェクトへ Google の play-services
全てを読み込むのは無駄なので、ネイルブックでは上記のように play-services
の中から必要なものだけを読み込んでいます。
使い方の説明については割愛しますが、ネイルブックでは Google Analytics と接続するコードをラップする static な Util 系メソッドを用意して、計測したい箇所からコールしています。また計測を色々なところに仕込んでいる場合はテストが大変(経験すると分かると思いますがユーザイベントを伴う非同期なクライアント・アプリケーションに計測を仕込むのは難しい)なので、デバッグ用のログ出力もされるようにしてあります。
⑨ Android Design Support Library
サイト:http://googledevjp.blogspot.jp/2015/07/android-design-support-library.html
※ Googleのブログです
Google 公式のライブラリです。マテリアルデザインの導入が簡単になります。ネイルブックでは ToolBar や左メニュー、タブなど、全般的に利用しています。
dependencies {
compile 'com.android.support:design:23.0.1'
}
執筆時点では
23.1.1
が最新ですが、NavigationView
のヘッダが取得できないような挙動だったのでまだ最新バージョンは適用していません(もしかして回避する方法があるかも?)。
これも公式のライブラリなので色々なところに記事があると思うので使い方の説明については割愛します。
⑩ Google Material icons (Google)
厳密にはライブラリではないのですが^^; Google が公式で用意しているマテリアルアイコンです。ネイルブックでも、これで済むアイコンはこれで済ませています。アプリを利用するユーザさんも、慣れてるアイコンの方が分かり易いというメリットがあるかと思います。
Android Studio から利用する場合は Android Material Design Icon Generator Plugin を利用すると捗ります。こちらの投稿で紹介しました。
[番外] Android Studio のプラグイン
ライブラリではありませんが、私が利用している Android Studio のプラグインはこちらにまとめています。
ほか:MultiDex 対応
ライブラリをいろいろ導入していくと、メソッド数が 65K を超えコンパイルでエラーになってしまうことがあると思います。そうなった場合はプロジェクトを MultiDex に対応させる必要があります。
Android 5.0(Lollipop) 以上の端末向けであれば build.gradle
で multiDexEnabled true
とするだけなのですが、それ未満の端末向けに対応するには、次のようにサポートライブラリを導入します。
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
Application クラス等で、MultiDex を有効化します。
public class SomeApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
MultiDex.install(this);
}
}
}
おわりに
上記以外に、ネットワーク通信まわりは Volley、JSON まわりは GSON、そのほか Facebook / Twitter 連係用のライブラリ、GCM(プッシュ通知)用の Google ライブラリなどなど。ネットワーク通信に関しては Retrofit に置き換えたいなあと思いつつ、なかなか進んでない感じです。
以上、全てではありませんが、Android版ネイルブック で利用しているライブラリを紹介しました。
株式会社スピカでは一緒に切磋琢磨できるエンジニアの方を募集(Android以外も)していますので興味がある方は是非こちらをご覧ください! Android に関しては Kotlin や RxJava、Realm を試してみようという機運とそれを実現するための裁量もあり、結構いろいろなことにチャレンジできる良い環境だと思います^^