昨今、 Android アプリ開発者の周辺で OkHttp, Dagger, Retrofit といった Square Open Source 製のフレームワークがトレンドになっています。
気になりつつもこれまで触る機会がなかったので、ここで調べてみることにしました。
今回は以下のライブラリ, フレームワークがどういったものなのかをざっくり紹介します。
- Dagger
- Otto
- Picasso
- OkHttp
- Retrofit
- LeakCanary
Dagger
Java 用の Dependency Injection フレームワーク
DI というとどうしてもテストを思い浮かべてしまいますが、Dagger は、再利用可能で互換性のあるモジュールを簡単に作成する方法としてこれが有効であると提唱しています。
シンプルな実装は以下のようになります。
MainActivity.java
public class MainActivity extends Activity {
@Inject Object mInjectionObject;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dagger);
ObjectGraph objectGraph = ObjectGraph.create(new InjectionModule());
objectGraph.inject(this);
Toast.makeText(this, mInjectionObject.getClass().getName(), Toast.LENGTH_SHORT).show();
}
}
InjectionModule.java
@Module(injects = DaggerActivity.class)
public class InjectionModule {
@Provides @Singleton
Object provideInjectionObject(){
return new String();
}
}
依存性を注入するクラス ( provide〜という規則に従ったメソッドを持つ) と ObjectGraph クラス、そして各アノテーションを用いて DI を実現するようです。
ObjectGraph に渡すモジュールを変えることで、容易に注入するオブジェクトを切り替えられるようになっています。
依存関係のために、インスタンスを生成し保持するといったお決まりのコードを削減し、かつモジュールという単位で切り替えられるようにできると言った点で、スマートな開発に一役買うのではないでしょうか。
Otto
Android に向けて開発されたイベントバス
Otto は任意のモジュールで発生したイベントを任意のモジュールで受け取るといった実装において、それを仲介する機構を提供します。
シンプルな実装は以下のようになります。
public class MainActivity extends AppCompatActivity {
class EventObject{
EventObject(String message){
this.message = message;
}
public String message;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_otto);
Bus bus = new Bus();
bus.register(this);
bus.post(new EventObject("テスト"));
bus.unregister(this);
}
@Subscribe
public void onEvent(EventObject eventObject){
Toast.makeText(this, eventObject.message, Toast.LENGTH_SHORT).show();
}
}
Bus をインスタンス化し、イベントを受け取りたいインスタンスを register で登録します。
post メソッドで任意のインスタンスを渡すと、登録されているインスタンスの @Subscribe アノテーションが付与されたメソッドに伝わるようです。
上の実装ではイベントバスを使う意味をなくしてしまっていますが、複数のモジュール間で Bus を共有することで、キレイな Observer パターンを構築することができます。
主にコールバック地獄を解決する手段として一つの解になるのではないでしょうか。
Picasso
画像のダウンロード/キャッシュライブラリ
ワンラインで ImageView に画像をロードできることが売りのようです。
実装は以下のようになります。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_picasso);
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Picasso.with(this).load("https://i.imgur.com/DvpvklR.png").into(imageView);
}
}
バックにスレッドプールやメモリ/ディスクキャッシュを持っており、無駄なスレッドを立ち上げず、またコンテキストのライフサイクルに対してフリーである点が非常にスマートです。
コンセプトにもれず、取得失敗時のプレースホルダの設定や画像の加工までもがメソッドチェーンの中で完結させられるところもアプリの開発者には嬉しい点です。
ネットワークだけでなくリソースや外部ファイルも同様に取り扱うことができるので、画像をロードして表示するという用途では、使わない手はないのではないでしょうか。
OkHttp
HTTP/2 と SPDY に対応した Java 用 HTTP クライアント
最近 AOSP で使われはじめた、実績のある HTTP クライアントです。
シンプルな実装は以下のようになります。
public class OkHttpActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ok_http);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://api.github.com/users/octcat/repos").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(Response response) throws IOException {
final String responseBody = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OkHttpActivity.this, responseBody, Toast.LENGTH_SHORT).show();
}
});
}
});
}
}
同期/非同期、ヘッダのカスタマイズ、ファイルの POST や multipart POST、レスポンスキャッシュやリクエストのキャンセルなども、全て簡単に利用することができます。
OkHttp はクライアントとして十二分な機能を持っているので、少し高度な制御が必要な際などには心強いのではないでしょうか。
Retrofit
REST API クライアント
インタフェースから REST API クライアントを自動生成してくれるフレームワークです。
シンプルな実装は以下のようになります。
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_retrofit);
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(RetrofitClient.API_URL).build();
RetrofitClient retrofitClient = restAdapter.create(RetrofitClient.class);
retrofitClient.listRepos("octcat", new Callback>() {
@Override
public void success(List repos, Response response) {
}
@Override
public void failure(RetrofitError error) {
}
});
}
}
RetrofitClient.java
public interface RetrofitClient {
String API_URL = "https://api.github.com";
@GET("/users/{user}/repos")
void listRepos(@Path("user") String user, Callback> callback);
}
Repo.java
public class Repo {
public String id;
}
REST API クライアントはインタフェースしか記述していないことがポイントです。
レスポンスもシンプルな POJO を定義しているだけです。
通信処理、スレッドやライフサイクルの管理、レスポンスのパース処理などは全て Retrofit のフレームワークが実装を担ってくれます。
他のフレームワークに比べて非常に高級で、取り回しが効きづらそうではありますが、大量かつ変更が発生しやすい API 周りのコードを劇的に削減できることは非常に魅力的ではないでしょうか。
LeakCanary
Java 用メモリリーク検知ライブラリ
ランタイムにメモリダンプを行って、メモリリークを検知してくれるライブラリです。
シンプルな実装は以下のようになります。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
Application クラスに1行記述するのみです。
これだけでメモリリークを検知し、その詳細を通知もしくはホームに生成されるアイコンより呼び出される画面にて確認することができます。
コールバックやイベントバスによる参照、無名インスタンスを使った通信などの非同期処理など、開発者がどれだけ気をつけても全てのメモリリークを把握することは難しいでしょう。
たった1行追加するだけでメモリリークを自動的に検知してくれるのは非常に革新的ではないでしょうか。
まとめ
それぞれ最も基本となる部分のみの紹介となりましたが、これだけでも利用したいと思える場面がいくつも浮かんできます。
設計に大きく関わるフレームワークもあり、いきなり「使おう!」とはいきませんが、導入を検討するには十分な魅力があるのではないでしょうか。
