はじめに
新卒で入社してから2ヶ月が立ちました。Androidに少しはなれてきたかな…
ということで今回は、Daggerを使ってDIしていきたいと思います!
Dagger Hiltが、最近話題になってますね。
今後、Daggerにしろ、KoinにしろDIコンテナを使うことは必須だと思うので復習していきます!
※前回の続きです
Gradle
gradleにDaggerを追加します。
// Dagger
def daggerVersion = '2.26'
implementation "com.google.dagger:dagger:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
実装
Daggerのオブジェクトグラフに、あるクラスのインスタンスを取得する方法を追加する必要があります。
@Inject
アノテーションをつけることで、これを実現します。
今回、
ViewModelはRepositoryに依存していて、
RepositoryはDatabaseに依存しています。
ViewModel
class MainViewModel @Inject constructor(private val repository: TodoRepository) : ViewModel() {
val todoList = repository.allTodoList
fun insert(todo: Todo) = viewModelScope.launch {
withContext(Dispatchers.IO){
repository.insert(todo)
}
}
Repository
class TodoRepository @Inject constructor(private val todoDao: TodoDao) {
val allTodoList = todoDao.getAll()
@WorkerThread
suspend fun insert(todo: Todo) {
todoDao.insert(todo)
}
}
@Inject
アノテーションをつけることで、クラスのインスタンスの提供方法をDaggerに伝えることができました。
Module
Interfaceなど、直接インスタンス化できないものの提供方法をDaggerに伝える必要があります。
依存関係の定義をグループ化するには、@Module
アノテーションをつけます。
@Module
class DatabaseModule() {
@Singleton
@Provides
fun provideTodoDatabase(context: Context) =
Room.databaseBuilder(context,
TodoDatabase::class.java,
"database_name")
.build()
@Singleton
@Provides
fun provideTodoDao(todoDatabase: TodoDatabase) = todoDatabase.todoDao()
}
@Module
アノテーションをつけたクラスに、インスタンスの生成方法を@Provides
アノテーションで実現します。
Component
ComponentはDaggerがオブジェクトグラフを生成して、あるクラスのインスタンスを取得する役割があります。
Componentを実装するには、@Component
アノテーションをInterfaceにつけます。
@Singleton
@Component(
modules = [
DatabaseModule::class
]
)
Interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): AppComponent
}
fun mainViewModel(): MainViewModel
}
@Singleton
アノテーションをつけることで、Singletonを実現します。
また、ComponentにModuleクラスで定義した依存関係を追加するために、modules
パラメータに記述します。
@Component.Factory
アノテーションでは、Componentのインスタンス取得時に特別な処理を定義することができます。今回は、Daggerのオブジェクトグラフ生成時にContextを渡したいので、引数に@BindsInstance
アノテーションをつけます。
Aplication
AppComponent.Factoryを使い、AppComponentのインスタンスを取得します。
インスタンス取得時にContextを渡します。
class TodoApplication : Application() {
companion object {
lateinit var component: AppComponent private set
}
override fun onCreate() {
super.onCreate()
component = DaggerAppComponent.factory().create(applicationContext)
}
}
Activity
class MainActivity : AppCompatActivity() {
private val mainViewModel: MainViewModel by lazy {
TodoApplication.component.mainViewModel()
}
...
これでMainActivityにMainViewModelを提供することができました。
おわりに
Todoアプリの削除機能を実装する前に、Daggerを使ってDIしてみました!
もし間違った記述があるなら、コメントで教えてほしいです!!!
Dagger Hiltも、時間があったら触ってみようかな。