Dagger2 - Android Dependency Injection

#DIとは
Dipendency Injection(DI)、「オブジェクトの注入」のこと。

要するに、依存性を自由に差し替えれるようにすることで、テストを実行しやすくしたり(モックを差し込む)、オブジェクトをそれぞれ管理できるようになる。

#AndroidにおけるDIの必要性
例えば、SharedPreferencesにデータを保存したい場合、DIなしで実行すると、SharedPreferencesからデータをインスタンス化、保存、取得することになり、すべてアクティビティに似たような記述をしなければならない。
<img width="429" alt="スクリーンショット 2020-06-24 15.34.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309711/a4eace8d-ccb1-dd45-23e5-373f044109ad.png">

この方法でアプリが大きくなると、最悪の場合改修不可能になる可能性がある。

なのでSharedPreferencesを毎回アクティビティでインスタンス化する代わりに、別のクラスから注入するようにする。

<img width="442" alt="スクリーンショット 2020-06-24 15.37.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309711/30e177e3-d869-1743-e72c-7e969c4babb7.png">


#Dagger2とは？
2012年にSquareの開発者によって開発されたライブラリ。

Dagger1は、クラスのインスタンスを作成し、Reflectionを介して依存関係を注入するために使用されていた。
その後Googleの開発チームと協力して、Dagger2はReflectionsを使用しない、はるかに高速なバージョンが導入されることになった。

Dagger2は、コンパイル時のAndroid依存性注入フレームワークであり、Java仕様要求（JSR）330を使用し、注釈プロセッサを使用する。

Dagger2で使用される基本的なアノテーションは以下。

@Module: 最終的に依存関係として提供されるオブジェクト構築をするクラス
@Provides: オブジェクトを返すModuleクラス内のメソッドで使用される
@Inject: 依存関係が要求されたことを示す(コンストラクタ/フィールド/メソッドで使用される)
@Component: Moduleを要求するクラスへ依存関係を渡すためのブリッジクラス
@Singleton: 依存関係において、単一のインスタンスを作成することを示す

#Sample
```xml:main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.journaldev.dagger2.MainActivity">

    <EditText
        android:id="@+id/inUsername"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:hint="Username" />

    <EditText
        android:id="@+id/inNumber"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/inUsername"
        android:layout_margin="8dp"
        android:inputType="number"
        android:hint="Number" />

    <Button
        android:id="@+id/btnSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SAVE"
        android:layout_below="@+id/inNumber"
        android:layout_toLeftOf="@+id/btnGet"
        android:layout_toStartOf="@+id/btnGet"
        android:layout_marginRight="8dp"
        android:layout_marginEnd="8dp" />

    <Button
        android:id="@+id/btnGet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="GET"
        android:layout_below="@+id/inNumber"
        android:layout_alignRight="@+id/inNumber"
        android:layout_alignEnd="@+id/inNumber" />

</RelativeLayout>
```

Moduleで依存性を定義

```java:SharedPrefModule.java
package com.journaldev.dagger2;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;

@Module
public class SharedPrefModule {
    private Context context;

    public SharedPrefModule(Context context) {
        this.context = context;
    }

    @Singleton
    @Provides
    public Context provideContext() {
        return context;
    }

    @Singleton
    @Provides
    public SharedPreferences provideSharedPreferences(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context);
    }
}
```

Componentで依存クラスに渡すオブジェクトの定義

```java:MyComponent.java
package com.journaldev.dagger2;

import javax.inject.Singleton;
import dagger.Component;

@Singleton
@Component(modules = {SharedPrefModule.class})
public interface MyComponent {
    void inject(MainActivity activity);
}
```

依存先で必要な箇所に@injectを記述(そこに注入される)

```java:MainActivity.java
package com.journaldev.dagger2;

import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    EditText inUsername, inNumber;
    Button btnSave, btnGet;
    private MyComponent myComponent;
    @Inject
    SharedPreferences sharedPreferences;

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

        initViews();
        myComponent = DaggerMyComponent.builder().sharedPrefModule(new SharedPrefModule(this)).build();
        myComponent.inject(this);


    }

    private void initViews() {
        btnGet = findViewById(R.id.btnGet);
        btnSave = findViewById(R.id.btnSave);
        inUsername = findViewById(R.id.inUsername);
        inNumber = findViewById(R.id.inNumber);
        btnSave.setOnClickListener(this);
        btnGet.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            case R.id.btnGet:
                inUsername.setText(sharedPreferences.getString("username", "default"));
                inNumber.setText(sharedPreferences.getString("number", "12345"));
                break;
            case R.id.btnSave:
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putString("username", inUsername.getText().toString().trim());
                editor.putString("number", inNumber.getText().toString().trim());
                editor.apply();
                break;

        }
    }
}
```

#さいごに
雑ですが、以上がDagger2の説明です。
今後アップデートします。