Introduction à Dagger2 – Partie 2

Mise en place

Modules

Commençons par créer nos modules :

  • GithubModule permettant de produire le GithubService et le Storage
  • ContextModule permettant de fournir aux autre modules un Context

GithubModule.java

/**
 * Ce module permet de récupérer le GithubService et le Storage
 * Dagger2 va les crééer de façon unique (Singleton) et ils seront accessibles depuis le GithubComponent
 */
@Module
public class GithubModule {

    /**
     * Retourne un Storage à Dagger2, construit avec le Context, injecté par Dagger2
     * @param context Contexte de l'application, fournit par Dagger2
     */
    @Provides
    @Singleton
    public Storage provideStorage(Context context){
        return new Storage(context);
    }

    /**
     * Créé le GithubService via Retrofit, qui réaliser les appels webservices,
     * en utilisant le StorageModule afin de gérer les clés
     *
     * @param storage le Storage injecté par Dagger2 via le StorageModule
     */
    @Singleton
    @Provides
    public GithubService provideGithubService(final Storage storage) {
        return new RestAdapter.Builder()
                .setEndpoint(BuildConfig.URL_GITHUB)
                .setRequestInterceptor(new RequestInterceptor() {
                    @Override
                    public void intercept(RequestFacade request) {
                        String key = storage.getApiKey();
                        if (key != null) {
                            //ajoute aux header la ApiKey en clé bearer
                            request.addHeader("bearer", key);
                        }
                    }
                })
                .build()
                .create(GithubService.class);
    }
}

La construction du GithubService prend en entrée un Storage, ce qui indique à Dagger que nous avons besoin d’une dépendance vers un objet Storage.

J’ai ajouté l’annotation @Singleton à mes méthodes, afin de ne créer qu’une seule instance de GithubService et de Storage. La construction du Storage nécessite un Context, qui sera fournir par ContextModule

ContextModule

/**
 * Ce module sert à fournir le contexte de l'application
 */
@Module
public class ContextModule {

    private final Context context;

    /**
     * Nous ajoutons volontairement un constructeur qui prend un Context en entrée,
     * afin de lui fournir au runtime lors de la création de l'Application
     * @param context l'application créée
     */
    public ContextModule(Context context) {
        this.context = context;
    }

    /**
     * Permet à Dagger2 de récupérer le context
     * @return le context de l'application
     */
    @Provides
    Context provideContext() {
        return context;
    }

}

Il faudra donc au moment de la création de l’application lui donner une référence vers le contexte courant, nous verrons plus tard comment le faire.

Components

Comme indiqué précédemment, les components sont les injecteurs, ils seront utilisés directement afin de récupérer les dépendances dans notre code (activités, fragments …).

Nous aurons ici un GithubComponent, permettant d’injecter nos dépendances dans nos différents contrôleurs.

GithubComponent.java

Composant principale de ce tutoriel, GithubComponent va utiliser Dagger2 afin de créer le GithubService et le Storage.
J’ai marqué ce composant est un singleton, c’est à dire qu’il n’existe qu’un fois lors de l’exécution de l’application.

modules = {ContextModule.class, StorageModule.class, RestModule.class} indique que ce Component utilisera les fonctions indiquées en @Provide de StorageModule, ContextModule et RestModule afin de générer les GithubService et Storage.

@Singleton
@Component(modules = {ContextModule.class, StorageModule.class, RestModule.class})
public interface GithubComponent {
    GithubService githubService();
    Storage storage();

    //permet d'injecter une GithubService dans une instance de MainActivity
    void inject(MainActivity mainActivity);
}

Dagger Component

Première étape, définir le Application.class de notre projet :

<application
        android:name=".Application"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

C’est dans cette classe que nous allons définir notre GithubComponent
Application est une classe assez spéciale sous Android, c’est la seule qui est vraiment “Singletonnée”, nous utilisons ici cette spécificité pour stocker notre GithubComponent

public class Application extends android.app.Application {

    protected GithubComponent githubComponent;
    protected static Application application;

    @Override
    public void onCreate() {
        super.onCreate();

        application = this;

        //je créé mon githubcompoent, et le stock dans mon application
        githubComponent = DaggerGithubComponent.builder()
                .contextModule(new ContextModule(getApplicationContext())) //on fournit le context
                .build();
    }

    public static Application app() {
        return application;
    }

    //permet aux activités via .getApplication().appComponent() de récupérer le AppComponent
    public GithubComponent component() {
        return githubComponent;
    }

}

L’accès à ce dernier se fera de la façon suivante

Application.app().component()

Voici comment va fonctionner Dagger2 dans notre exemple

public class MainActivity extends AppCompatActivity {

    @Inject
    GithubService githubService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //injecte le GithubService
        Application.app().component().inject(this);

        //on peux maintenant utiliser notre webservice REST via Retrofit
        this.githubService.listRepos("florent37", new Callback<List<Repo>>() {
            @Override
            public void success(List<Repo> repos, Response response) {
                Toast.makeText(MainActivity.this, repos.size() + " repos", Toast.LENGTH_LONG).show();
            }

            @Override
            public void failure(RetrofitError error) {
                Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

}

Dagger est un outil très puissant, il est possible de faire bien plus que ce que je vous ai présenté lors de cette introduction.
Il est maintenant supporté par Google et rendu disponible sur Github, je vous invite donc à consulter la documentation officielle http://google.github.io/dagger/ afin d’apprendre à maitriser cet outil.

Les sources de ce tutoriel sont disponibles à l’adresse suivante : github

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *