[Codelabs]「Android アプリでの Hilt の使用」をやってみる

# はじめに
本記事は、Codelabsの[AndroidアプリでのHiltの使用](https://developer.android.com/codelabs/android-hilt)をやってみた際のログです。
詰まった箇所について述べています。

# 実行環境
PC: `MacBook Air (M1, 2020)`
OS: `macOS Big Sur 11.5.2`
チップ: `Apple M1`
メモリ: `16 GB`
Android Studio:

```
Android Studio Arctic Fox | 2020.3.1 Patch 2
Build #AI-203.7717.56.2031.7678000, built on August 27, 2021
Runtime version: 11.0.10+0-b96-7249189 aarch64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 11.5.2
GC: G1 Young Generation, G1 Old Generation
Memory: 1280M
Cores: 8
Registry: external.system.auto.import.disabled=true
Non-Bundled Plugins: IdeaVIM, Dart, wu.seal.tool.jsontokotlin, org.jetbrains.kotlin, io.flutter, com.jetbrains.kmm
```

# やってみる
実際にCodelabsの通りにやってみる。
## 設定方法
リポジトリをクローンして実行してみる。

```bash
git clone https://github.com/googlecodelabs/android-hilt
```

### kaptのエラー
実行しようとしたところ、以下のkaptのエラーが出力された。

```
Execution failed for task ':app:kaptDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask$KaptExecutionWorkAction
   > java.lang.reflect.InvocationTargetException (no error message)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
```

stacktraceオプションを用いて、詳細なエラーログを出力したところ、以下のエラーが出力された。

```
Execution failed for task ':app:kaptDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask$KaptExecutionWorkAction
   > java.lang.reflect.InvocationTargetException (no error message)

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:kaptDebugKotlin'.

・・・

Caused by: java.lang.Exception: No native library is found for os.name=Mac and os.arch=aarch64. path=/org/sqlite/native/Mac/aarch64
	at org.sqlite.SQLiteJDBCLoader.loadSQLiteNativeLibrary(SQLiteJDBCLoader.java:333)
	at org.sqlite.SQLiteJDBCLoader.initialize(SQLiteJDBCLoader.java:64)
	at androidx.room.verifier.DatabaseVerifier.<clinit>(DatabaseVerifier.kt:71)
	... 50 more
```

### kaptのエラーの対処
調べたところ、stack overflowの[Caused by: java.lang.Exception: No native library is found for os.name=Mac and os.arch=aarch64. path=/org/sqlite/native/Mac/aarch64](https://stackoverflow.com/questions/68884589/caused-by-java-lang-exception-no-native-library-is-found-for-os-name-mac-and-o)という記事を見つけた。

記事によると、`kapt "org.xerial:sqlite-jdbc:3.34.0"`をroom-compilerの前に追加してやれば良いそうなので追加してみる。

変更を加えた`build.gradle(:app)`のRoomのdependencies部分を以下に示す。

```gradle
// Room
kapt "org.xerial:sqlite-jdbc:3.34.0"
implementation "androidx.room:room-runtime:2.3.0"
kapt "androidx.room:room-compiler:2.3.0"
```

### 再度実行
再度、実行してみると実行することができた。

## プロジェクトへの Hilt の追加
読むだけ。

## アプリでの Hilt
`@HiltAndroidApp`を加えるだけ。

## Hilt を使用したフィールド注入
### LogsFragment
`LogsFragment`に`@AndroidEntryPoint`を加える。
`logger`と`dateFormatter`に`@Inject`を加える。
`populateFields`を削除する。

### DateFormatter
`DateFormatter`のコンストラクタに`@Inject`を加える。

### LoggerLocalDataSource
`LoggerLocalDataSource`のコンストラクタに`@Inject`を加える。

## インスタンスのスコープのコンテナに対する設定
LoggerLocalDataSourceの@Singletonを加える。

## Hilt モジュール
### モジュールの作成
`DatabaseModule`を作成しようとしたところ、`ApplicationComponent`が存在していなかった。
調べたところ、stack overflowの[error: cannot find symbol @dagger.hilt.InstallIn(value = {ApplicationComponent.class})](https://stackoverflow.com/questions/65988186/error-cannot-find-symbol-dagger-hilt-installinvalue-applicationcomponent-c)にて、Dagger Version 2.30にてDeprecated、Dagger Version 2.31にて削除されている。
`ApplicationComponent`の代わりに、`SingletonComponent`を使えとのこと。

### @Provide を使用したインスタンスの提供
`provideLogDao`を作成。
`provideDatabase`を作成。

### アプリの実行
`MainActivity`に`@AndroidEntryPoint`を加える。

## @Bind を使用したインターフェースの提供
`NavigationModule`を作成。
`AppNavigatorImpl`に`@Inject`を加える。
`MainActivity`の`AppNavigator`に`@Inject`を加える。
`ButtonsFragment`に`@AndroidEntryPoint`を加える。
`ButtonsFragment`の`LoggerLocalDataSource`と`AppNavigator`に`@Inject`を加え、不要なメソッドを削除。
`LogApplication`から`ServiceLocator`の使用を削除。

## 識別子
`LoggerDataSource`を作成。
`LogsFragment`の`logger`変数の型を`LoggerDataSource`に設定。
`ButtonsFragment`の`logger`変数の型を`LoggerDataSource`に設定。
`LoggerLocalDataSource`のインターフェースを実装。
`LoggerInMemoryDataSource`を作成。
`LoggerInMemoryDataSource`に`@Inject`と`@ActivityScoped`を加える。
`LoggingModule`の作成。

## UI テスト
`build.gradle(:app)`に以下のdependenciesを追加。

```gradle
// Hilt testing dependency
androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
// Make Hilt generate code in the androidTest folder
kaptAndroidTest "com.google.dagger:hilt-android-compiler:$hilt_version"
}
```

`CustomTestRunner`を作成。
`build.gradle(:app)`に`testInstrumentationRunner`を設定。
`AppTest`に`@HiltAndroidTest`を加え、`hiltRule`を作成。

## @EntryPoint アノテーション
`LogDao`に`selectAllLogsCursor`と`selectLogById`を追加。
`LogsContentProvider`を作成。
`LogsContentProvider`に`LogsContentProviderEntryPoint`を追加。

# メモ
- abstract class
- interface
- annontation class
- LinkedListとArrayList