Hello Guice! Androidアプリの作成

実際に使ってみる

Hello World!を Guiceで作る

  • GreetingService
    名前を入力すると挨拶を返すサービスのインターフェース
  • StandardGreetingService
    実際にGreetingServiceの実装。普通の挨拶を返す
  • Client
    GreetingServiceを利用するクラス
  • GreetingModule
    GreetingServiceのインタフェースと実装を結びつけるモジュール

GreetingModuleクラスですが、DI Containerにおける設定ファイル 「このインターフェースが要求されたこの実装を使う」といった設定はこの中に書かれる形になります。

Guiceの特徴として設定ファイルである Moduleがコンパイラを経由する事で XMLファイルのようにタイプミスが実行時までわからないといった事を防げます。

実装

Androidの Application Projectに変更を加えていきます。

layoutファイル

テキスト表示用にTextViewを追加

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/main_activity_textview"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world"
        tools:context=".MainActivity">

</RelativeLayout>

サービスのインターフェース

package local.exguice1;

public interface GreetingService {
    String greetingTo(String to_name);
}

サービスの実装

package local.exguice1;

public class StandardGreetingService implements GreetingService {
    public String greetingTo(String to_name) {
        return to_name + "さん、こんにちは!";
    }
}

サービスを利用するクライアント

ポイントは @Inject というfieldに付けられたアノテーション。

package local.exguice1;

import javax.inject.Inject;

public class Client {

    @Inject
    private GreetingService service;

    public String getMessage() {
        return service.greetingTo("Google Guice");
    }

}

GreetingServiceを利用するためのModule

bind関数を呼び出して GreetingServiceとして StandardGreetingServiceを注入

package local.exguice1;

import com.google.inject.AbstractModule;

public class GreetingModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(GreetingService.class).to(StandardGreetingService.class);
    }

}

MainActivity

やってることは Injectorを使ってインスタンスを得るようにしています。

Injectorのインスタンス作成には 設定ファイル代わりの Moduleを指定する。

package local.exguice1;

import com.google.inject.Guice;
import com.google.inject.Injector;</span>

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Injector injector = Guice.createInjector(new GreetingModule());

        Client client = injector.getInstance(Client.class);

        TextView textView = (TextView) findViewById(R.id.main_activity_textview);

        textView.setText(client.getMessage());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

まとめ

@Injectアノテーションを付けられたフィールドがfield injectionの対象

Module.configure内で Interface と Implementation を bindしている。 bind(Interface).to(Implementation); の方法は Linked Bindingsと呼ばれる。

injectorから getInstanceすると @Injectフィールドに 指定実装が注入された インスタンスが得られて利用できます。

Interfaceに対する Implementationの注入を Moduleに追い出せた形。