Androidアプリ開発を何も知らない人がキャッチアップするまでの記録

## ニュース

### Android15リリース

2024/3 にプレビューが公開。4月からベータ期間となり、6月からは新規機能の公開は終了してバグ修正のみとなっていき、8月に正式公開となる。

- 広告SDKが機密情報を窃取したりしないよう、広告SDKなども通常アプリと同じくサンドボックス空間内に閉じ込めるPrivacy Sandbox機能
- 開発者向け アプリ内に埋め込んだファイルの改竄検出のためのAPIが追加された。
   - [FileIntegrityManager](https://developer.android.com/reference/android/security/FileIntegrityManager#setupFsVerity(java.io.File))

## Android アップデート対応

こちらの記事で一通りまとめてくれている。
[Zenn - Androidでの新規リリースとアップデート対応](https://zenn.dev/s_ryuuki/articles/531e958e033988e7b2f1)

## 参考書

書籍については、内容をまとめるのは著作権的に問題があるのと、量も多く難しいため、読んだ書籍と内容のポイント、自分で調べ直した部分があればそこを記載します。

- Jetpack Compose 基礎から学ぶAndroidアプリの宣言的UI, 臼井篤志, 技術評論者, 2024

### Androidアプリ開発の極意, 木田学 ほか, 技術評論社, 2017

やや古い本だが、Activityベースのアプリについて様々な実務ポイントを紹介している。

#### Activity Launchmode
Activityの表示形式について5種類がある。この本の執筆時に比べて一種類増えている。

[Google - App Manifest File - Activity](https://developer.android.com/guide/topics/manifest/activity-element#lmode)

#### Activity 名やアイコンの動的な変更

Acticity Aliasを利用することで、一つのActivityについて、名前やアイコンを動的に変えることもできる。

[Androidのアプリアイコンとタイトルを動的に変更する](https://qiita.com/temoki/items/3fa4acc0a897bbbbbc8f)

#### Service

UIを持たないクラスで、アクティビティが終了してもバックグラウンドで動作を続けられるクラス。例えば、通信などを行うクラスなど。

[【Android】サービスの概要とサンプルコード](https://qiita.com/kenmaeda51415/items/c80065a48bd11d26df84)
[Google Developers - サービスについて](https://developer.android.com/develop/background-work/services?hl=ja)
[Google Developers - サービスをテストする](https://developer.android.com/training/testing/other-components/services?hl=ja)

#### ブロードキャスト

[Android developers - ブロードキャストの概要](https://developer.android.com/develop/background-work/background-tasks/broadcasts?hl=ja#restrict-broadcasts-permissions)

#### パーミション

カメラアクセス、連絡先アクセス、位置情報取得など、ユーザーに対してセンシティブな影響のある機能は、ユーザーの許諾を得る必要がある。

[Google Develoer - Android での権限](https://developer.android.com/guide/topics/permissions/overview?hl=ja)
[Google Developers - Manifest.permission](https://developer.android.com/reference/android/Manifest.permission#BIND_VOICE_INTERACTION)

ユーザーがNever Ask Again（二度と権限許可ダイアログを表示するな）
を選択したかを判定するために、権限ダイアログを出す前に[shouldShowRequestPermissionRationale](https://developer.android.com/reference/androidx/core/app/ActivityCompat#shouldShowRequestPermissionRationale(android.app.Activity,java.lang.String))を呼んでおくことが推奨される。

[Android M Permissions : Confused on the usage of shouldShowRequestPermissionRationale() function](https://stackoverflow.com/questions/32347532/android-m-permissions-confused-on-the-usage-of-shouldshowrequestpermissionrati)

Android Mより、許可がないのに許可が必要な操作をしようとすると、SecurityExceptionが発生するようである。

[Stack Over Flow - Android security exception for permission listed in manifest file](https://stackoverflow.com/questions/37000294/android-security-exception-for-permission-listed-in-manifest-file)

#### Dozeモード、App Standby

アプリを使わずにバッテリーに接続もせずに放置していると、これらの省電力モードに突入し、アプリの機能が制限される。

[Doze とアプリ スタンバイ用に最適化する](https://developer.android.com/training/monitoring-device-state/doze-standby?hl=ja)

### RelativeLayout, LinearLayout

RelativeLayoutは親、各部品同士の相対的な位置関係を比較的自由に設定できる。Linear Layoutは、横一列または縦一列の単純な配置となる。

[メモ：ビューの配置 - LinearLayout と RelativeLayout](https://monoworks.co.jp/post/android_develop_memo_2015091101/)
[LinearLayoutとRelativeLayoutの配置属性メモ](https://qiita.com/yamacraft/items/5846bd24829eb3d57509)
[LinearLayoutとRelativeLayoutの使い方をまとめてみた](https://korsakov.hatenadiary.org/entry/20110131/1296504108#a12)

部品同士に固定サイズの隙間を設定したい場合はSpaceを設定できる。可変長の隙間を設定したい場合はViewを利用できる。

[Adding blank spaces to layout](https://stackoverflow.com/questions/6352140/adding-blank-spaces-to-layout)

パフォーマンスについて、一般には複雑になればなるほどパフォーマンス的な問題が発生する可能性がある。あまりに複雑な画面の場合、減らせる部品は減らすなどの配慮がいるだろう。

[Is a RelativeLayout more expensive than a LinearLayout?](https://stackoverflow.com/questions/4069037/is-a-relativelayout-more-expensive-than-a-linearlayout)

### Android ユニットテスト ヒッチハイク・ガイド, okuzawats, 2024, Retrieved from https://zenn.dev/okuzawats/books/android-unit-testing

### Android 依存性注入 ヒッチハイク・ガイド, okuzawats, 2024, Retrieved from https://zenn.dev/okuzawats/books/android-dependency-injection

## 公式実装例

- さまざまなパターンのアーキテクチャによるAndroidアプリ(kotlin)の実装例を格納したGoogle公式リポジトリ
   - [android/architecture-samples](https://github.com/android/architecture-samples)

- UI・マテリアルデザインのサンプルアプリ
   - [android/compose-samples](https://github.com/android/compose-samples)

- Jetpackを利用したサンプル
   - [android/sunflower](https://github.com/android/sunflower)
   - [ViewModel and State in Compose](https://developer.android.com/codelabs/basic-android-kotlin-compose-viewmodel-and-state?hl=zh-cn#10)
       - Jetpack Compose, ViewModel, Flowを利用した典型的なMVVMの紹介。
   - 上級編 [android/architecture-components-samples/GithubBrowserSample/](https://github.com/android/architecture-components-samples/tree/master/GithubBrowserSample)

- ネットワークへのアクセスや認証など、実際にストアで公開されるアプリに近い機能を備えたアプリ
   - [android/nowinandroid](https://github.com/android/nowinandroid)

## 公式UIガイドライン

[Introducing the Android Design Hub: The ultimate resource for building exceptional user interfaces across all form factors](https://android-developers.googleblog.com/2023/05/introducing-android-ui-design-hub.html?m=1)

[Material Design (3)](https://m3.material.io)
[androidx.compose.material3](https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#ModalNavigationDrawer(kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.material3.DrawerState,kotlin.Boolean,androidx.compose.ui.graphics.Color,kotlin.Function0))

Material Designに乗っ取ったアプリのさまざまなデザインテンプレートが外部会社により販売されている。
[MATERIAL DESIGN KIT](https://materialdesignkit.com/templates/)

## その他、実装例

- アーキテクチャ、UI(Jetpack Compose)の参考など

[kliment-jonceski/JetPackPlaygroundApp](https://github.com/kliment-jonceski/JetPackPlaygroundApp/blob/master/JetPackPlaygroundApp/app/src/main/java/joncheski/kliment/com/jetpackplaygroundapp/ui/datastoreactivity/DataStoreViewModel.kt)

- JetpackCompose 実装例（臼井篤志氏）
    - [compose-book-samples](https://github.com/usuiat/compose-book-samples)

## デザイン

デザイナーとエンジニアの連携ツールはいろいろあるがAndroid, iOSでおすすめなのはFigma。

- 紙っぺら一枚のデザインでは具体的にどう実装するのかわからずエンジニアがよしなに実装するなどという不具合が発生しうる。しかしFigmaは状態の変動に応じて同一の部品や画面が細かく変化するUIを表現できる。
- ツールを導入すれば、Jetpack Composeでどう実装するのかのコードを出力できたりもする。

参考 

- [Figma](https://www.figma.com)
- [Figma for beginners (4 parts)](https://help.figma.com/hc/en-us/sections/4405269443991-Figma-for-beginners-4-parts)
- [デザインからアプリ実装まで一貫したデザインシステムを構築するベストプラクティス](https://speakerdeck.com/shuzo/tesainkaraahurishi-zhuang-mate-guan-sitatesainsisutemuwogou-zhu-suruhesutohurakuteisu?slide=51)

## Intent

> インテントとは、「何かを行う意図」という意味で、幅広い役割として利用可能ですが、特定のアクションをリクエストする時に使用できる、メッセージングオブジェクトのことを意味しています。例えば別の画面を開きたい時に、AndroidではActivity単位で画面が作られますが、「開いている画面に対して別の画面を開いてください」とアプリにメッセージとして伝えることで、別の画面を開くことが可能になります。
　今回は基本的な使い方として、「Activityを起動する」、「Serviceを起動する」、「ブロードキャストを配信する」の3点をIntentを使った例として紹介します。

[【Androidアプリ開発】Intentとは、Intentの使い方とは。](https://techgrowup.net/2021/05/18/android-intent/)

- [インテントとインテント フィルタ](https://developer.android.com/guide/components/intents-filters?hl=ja)
  - 他アプリから自分のアプリのIntentを呼び出されない様にするには、`exported`属性を`false`にする。特に理由がなければfalseとすべきだろう。 




## Jetpack Compose
Android版の
flutter, SwiftUIとでもいうべき、宣言的に簡潔にUIが記述できるライブラリ。https://qiita.com/kota_2402/items/7bbdd87be8024785e25b
[Compose でのレイアウト](https://developer.android.com/jetpack/compose/layout?hl=ja#responsive-layouts)

`@Composable`アノテーションのついた関数によって、宣言的にUIを構築する。

バージョン２と３があるが（2023/7現在）、新しくアプリを作り始めるのであれば最新版を選択すべきだろう。

[Compose でマテリアル 2 からマテリアル 3 に移行する](https://developer.android.com/jetpack/compose/designsystems/material2-material3?hl=ja#m2_2)

### 基本の考え方

- 何か一つのパラメータが変更されたからといって全ての`@Composable`関数が再描画されるわけではない。それだと膨大なコストがかかってしまう。一部の`@Composable`関数のみが再描画されることがありうる。それどころか、一つの`@Composable`関数の中のUI部品のうち、必要なUI部品のみが再描画の対象となり、他の部分は再描画されないということさえありうる。
- 再描画が終わらないうちにもう一度再描画の指示がされた場合は、終わっていなかった再描画はキャンセルされる。
- 場合によっては、`@Composable`関数が UI アニメーションのフレームごとに実行され、一秒間に数百回も実行される可能性がある。高価な副作用を`@Composable`関数に書いてしまうと、パフォーマンスが悪化する。
    - そのため、`@Composable`関数のなかに「UIを描画する」以外の副作用は一切書くべきではない。例えば、共有の領域にある変数を変更するなど。そのような副作用が必要な場合は、`@Composable`関数のなかで直接行うのではなく、`onClick`などのコールバックを`@Composable`関数に渡して行うようにする。

- 以下、引用

```kotlin:Test.kt
@Composable
@Deprecated("Example with bug")
fun ListWithBug(myList: List<String>) {
    var items = 0

    Row(horizontalArrangement = Arrangement.SpaceBetween) {
        Column {
            for (item in myList) {
                Text("Item: $item")
                items++ // Avoid! Side-effect of the column recomposing.
            }
        }
        Text("Count: $items")
    }
}
```

- 以上、引用 [Compose の思想](https://developer.android.com/jetpack/compose/mental-model?hl=ja#simple-example)より
- この`@Composable`関数の中では、itemsというプロパティを更新しているが、再描画が行われる回数はスキップされたりし厳密なものではないことから、このような副作用を記載してはいけない。
- kotlin 2.0.20以降はStrong Skip Modeが標準となる。コンポーザブルの引き数が非安定な型（変数が含まれる型など）の場合、前は常にコンポーザブルの更新が走っていた。今後は、非安定な型（変数が含まれる型など）の場合、引数に渡されたのが前と同一インスタンスの場合は更新をスキップし、同一インスタンスでない場合は更新を行うようになる。
    - [Strong skipping mode](https://developer.android.com/develop/ui/compose/performance/stability/strongskipping)
    - [Strong Skipping Mode の検証で分かったこと](https://qiita.com/Xylocopa/items/bb66032203393b8f1899)


### 状態 State について

↑で`@Composable`関数の中に変数を作ってそれを変更することで状態管理などをしてはいけないと述べた。普通の変数ではなく、`remember` または `rememberAsSaveable`という関数を用いて、`MutablState<T>`という型の変数を設ければ、`@Composable`関数の中で状態管理をしても良い。

例えば以下のようになる。

```kotlin:example.kt
val mutableState = remember { mutableStateOf(default) }
// or
var value by remember { mutableStateOf(default) }
// or
val (value, setValue) = remember { mutableStateOf(default) }
```

全体の例としては以下のようになる。テキストフィールドにユーザーが何か入力すると、その文字によって表示を変える例である。remember関数を用いて、MutableState<String>という型の状態`name`を保持させている。

```kotlin:HelloContent.kt
@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       var name by remember { mutableStateOf("") }
       if (name.isNotEmpty()) {
           Text(
               text = "Hello, $name!",
               modifier = Modifier.padding(bottom = 8.dp),
               style = MaterialTheme.typography.h5
           )
       }
       OutlinedTextField(
           value = name,
           onValueChange = { name = it },
           label = { Text("Name") }
       )
   }
}

```

また、Androidで用いられるオブザーバブルな型から値を持ってきて、Composeで使うMutableState<T>へと簡単に変換する関数も用意されている:

- [`Flow`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)の場合: [collectAsStateWithLifeCycle](https://developer.android.com/reference/kotlin/androidx/lifecycle/compose/package-summary)関数 または [collectAsState](https://developer.android.com/reference/kotlin/androidx/compose/runtime/package-summary)を使う。
- [`LiveData`](https://developer.android.com/reference/kotlin/androidx/compose/runtime/livedata/package-summary?hl=ja)の場合: [observeAsState](https://developer.android.com/reference/kotlin/androidx/compose/runtime/livedata/package-summary?hl=ja#(androidx.lifecycle.LiveData).observeAsState(kotlin.Any))関数を使う。

`@Composable`関数内部で、rememberなどを用いて状態を持っている場合これをステートフルと呼ぶ。逆に、`@Composable`関数内部では状態を持たず、むしろ関数への引数として必要な値やクロージャーを渡して運用するようにする場合もあり、これはステートレスと呼ぶ。ステートレスの場合は、例えばViewModelなど外側で状態管理をすることになるだろう。

慣習として、表示内容は同じだが、ステートレスとステートフルな関数2つを用意する場合がある。↓

```kotlin:example.kt
@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.h5
        )
        OutlinedTextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Name") }
        )
    }
}

```



以上、コードはこのページより引用した： [状態と Jetpack Compose](https://developer.android.com/jetpack/compose/state?hl=ja)

`remember`は、端末の向きの切り替え、ダークモード切り替えなどアクティビティの破棄と再構成がされる場合は値がリセットされてしまう。その場合でも値を保持したい場合は、代わりに`rememberSaveable`を使うと良い。自分独自の型を`rememberSaveable`にそのままでは渡せないので、`Saver`というcompanion objectを定義する方法が用意されている。
[](https://star-zero.medium.com/remembersaveable-と-saver-3870051fd9fc)

### [ComponentActivity](https://developer.android.com/reference/androidx/activity/ComponentActivity)
    
- Compose-onlyのアプリで使うアクティビティだが、通常はサブクラスの`FragmentActivity`や`AppCompatActivity`を使う。
- [ComponentActivity vs AppCompactActivity in Android Jetpack Compose](https://stackoverflow.com/questions/67891362/componentactivity-vs-appcompactactivity-in-android-jetpack-compose)

### 副作用について
#### [LaunchedEfect](https://developer.android.com/jetpack/compose/side-effects?hl=ja)

 - 一つ目の引数（key）に何らかの変更が加わるたびに、二つ目の引数で指定したクロージャ内の処理を実行する。実行中にもう一度実行指示が出た場合は、実行中の処理をキャンセルし、新しい処理の方に行く。
     - [サンプルで理解するJetpack Composeの副作用の仕組み](https://zenn.dev/kaleidot725/books/jetpack-compose-sideeffect-samples)

### コンポジションツリーのどこからでも閲覧できるstaticのような仕組みはないか？

あります。CompositionLocalという仕組みで、さまざまな値をコンポーズのUI部品のどこからでも一行コードを書くだけで閲覧できるようになります。もちろんバグの元になるので、いろんなところから値を変更するような使い方は避けた方がいいでしょう。

[Locally scoped data with CompositionLocal ](https://developer.android.com/develop/ui/compose/compositionlocal)
[CompositionLocalをうまく使おう](https://qiita.com/t_nana/items/49df836fb25779083618)

#### その他

- [Compose における副作用 ](https://developer.android.com/develop/ui/compose/side-effects?hl=ja)
- [Jetpack Compose副作用 関数整理](https://qiita.com/kk__777/items/a0d5ea39ef2622b5b6d9)

### Modifier

ComposeのUI部品について、背景色、パディング、高さや横のサイズ、輪郭などなど、さまざまな設定を付与できる。

[Android developer - Compose 修飾子のリスト](https://developer.android.com/jetpack/compose/modifiers-list?hl=ja)
[Qiita - Jetpack Compose Modifier(修飾)](https://qiita.com/Ryosuke-Android/items/98761090e14f404f0884)
[Jetpack Compose Modifier徹底解説](https://docs.google.com/presentation/d/1cx0796Gc0qLlzUMJwWTz94PqSZ60LHMFmAdz0m7T3kA/edit#slide=id.p1)

複数のModifierを使った場合、Modifierが適用されるのは、上から順である。

[Modifiers in Jetpack Compose — Basic Concepts to Get You Started](https://medium.com/swlh/modifiers-in-android-compose-basic-concepts-to-get-you-started-83387debd928)



#### 部品の角を丸くしたい。

`.clip`モディファイアを使えば可能である。四隅のうち、特定の角のみを丸くすることも可能である。以下は、下方の角のみを丸くした例。

```home.kt
        modifier = modifier
            .clip(shape = RoundedCornerShape(0.dp, 0.dp, 25.dp, 25.dp))
```



### Icons

ボタンなどで使えるアイコンとしてMaterial Iconが用意されている。

[Material Icons](https://fonts.google.com/icons)

以下のように用いる。

```kotlin:HomeScreen.kt
Icon(Icons.Rounded.Favorite, contentDescription = "Favorite")
```


### Scaffold

UI部品の最下層に設置することが多く、他の画面（UI部品）の他、アプリバー、フローティングアクションボタン、スナックバー、ドロワーなどを設定できる。

Scaffoldのラムダ式には引数としてpaddingValuesという値が渡され、子UI部品にModifier経由でパディングとして設定することで、アプリバーなどの分の余白を考慮したデザインとできる。

- 以下、引用

```kotlin:Screen.kt
Scaffold(/* ... */) { contentPadding ->
    // Screen content
    Box(modifier = Modifier.padding(contentPadding)) { /* ... */ }
}
```

- 以上、引用 [マテリアル コンポーネントとレイアウト - Scaffold](https://developer.android.com/jetpack/compose/layouts/material?hl=ja#scaffold) より

#### AppBar

Scaffoldに設定できるアプリ上部のバー。
[androidx.compose.material - TopAppBar](https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#TopAppBar(androidx.compose.ui.Modifier,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.unit.Dp,androidx.compose.foundation.layout.PaddingValues,kotlin.Function1))

Material3 では`CenterTopAppBar`というのがあるので、これを使うとタイトル部分を中央寄りにできる。

[CenterAlignedTopAppBar](https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#CenterAlignedTopAppBar(kotlin.Function0,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,androidx.compose.foundation.layout.WindowInsets,androidx.compose.material3.TopAppBarColors,androidx.compose.material3.TopAppBarScrollBehavior))
[How to align title at layout center in TopAppBar?](https://stackoverflow.com/questions/67497414/how-to-align-title-at-layout-center-in-topappbar)



### Column, Row, LazyColumn, LazyRow, LazyVerticalGrid 

要素数が固定のリストを表示したいときはColumn, RowでOKだが、要素数がいくつかが実行時まで決まらず、多くの要素数があると想定される場合は、パフォーマンス上の問題が生じることから、LazyColumn, LazyRow, LazyVerticalGridを代わりに使う。

[Android Developers - リストとグリッド](https://developer.android.com/jetpack/compose/lists?hl=ja)
[Jetpack Compose Playground - LazyVerticalGrid](https://foso.github.io/Jetpack-Compose-Playground/foundation/lazyverticalgrid/)

#### Column, Rowで空いたスペースを画面いっぱいに埋めるようにしたい。
Column, Rowの子として以下のような`Spacer`を入れれば良い。

`Spacer(modifier = Modifier.weight(1.0f))`

なお`weight`がついた子が複数ある場合は、weightの値の割合に基づいて空いているスペースが分配されるとのこと。

[Google Developers - 修飾詞](https://developer.android.com/jetpack/compose/modifiers?hl=ja#weight-in-row-and-column)

### Box

縦(Z軸)にUI要素を重ねていきたいときに使える。以下は、丸い背景の上にアイコン画像を重ねてみた例である。

```kotlin:HomeScreen.kt
            Box(
                modifier = Modifier
                    .size(90.dp)
                    .clip(CircleShape)
                    .background(colorResource(id = type.colorResourse())),
                contentAlignment = Alignment.Center,
            ) {
                Image(
                    imageVector = type.icon(),
                    contentDescription = type.contentDescription(),
                    modifier = Modifier
                        .size(45.dp)// Making this Image 90.dp cause the icon gettting big so much, so setting 45.dp. Instead, made Box 90.dp.
                        .clip(CircleShape)
                        .background(colorResource(id = type.colorResourse())),
                    colorFilter = ColorFilter.tint(Color.White)
                )
            }
```


### `Button`, `OutlinedButton`, `TextButton`

見た目の目立つ度合いに応じて、三種のボタンがJetpack Composeにて用意されている。


| `Button` | `OutlinedButton` | `TextButton` |
|:-----------:|:------------:|:------------:|
|    ![スクリーンショット 2023-04-02 17.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/f20f8b4b-0958-db73-a77c-e2aedf5624a5.png)    |    ![スクリーンショット 2023-04-02 17.47.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/a379f718-1486-f845-f5e7-419d72d11b48.png)     |     ![スクリーンショット 2023-04-02 17.47.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/a5b0cdbf-f42d-c334-1099-7084f28d728d.png)     |

※ 画像はAndroid公式ドキュメントより引用

- 色を変える場合は`colors`引数に`ButtonColors`という型のオブジェクトを渡す。

```kotlin:test.kt
Button(
    onClick = tappedPasteButton,
    shape = ButtonDefaults.filledTonalShape,
    colors = ButtonDefaults.buttonColors(
        colorResource(id = R.color.light_gray),
        colorResource(id = R.color.white),
        colorResource(id = R.color.black),
        colorResource(id = R.color.black),
    ),
) {
// content
}
```
[ButtonDefaults](https://developer.android.com/reference/kotlin/androidx/compose/material3/ButtonDefaults#buttonColors(androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color))
[JETPACK COMPOSE: BUTTONコンポーザブルを使う](https://techbooster.org/android/ui/18475/)

### 共通要素遷移(画面遷移の際に、あるUI要素が拡大縮小移動するなどして次の画面のUI要素へとシームレスに変形する画面遷移)

Jetpack composeではModifier.sharedElementというモディファイアを用いる。

[Google Developers - 共有要素遷移をカスタマイズする](https://developer.android.com/develop/ui/compose/animation/shared-elements/customize?hl=ja)
[Jetpack Composeにおける
Shared Element Transitionsの実例と導入方法またその仕組み](https://docs.google.com/presentation/d/1kmKLeTsic2Fixxu63xFjVwu5wE1AC07HzGvD5mS9T0o/edit#slide=id.g2f7714da44f_0_538)

### Typograhy

Textなどの文字の大きさを変えることができます。

[Typography - Material Design3](https://m3.material.io/styles/typography/type-scale-tokens#40fc37f8-3269-4aa3-9f28-c6113079ac5d)
[［Jetpack Compose］TextStyle を適用する Text コンポーザブルを予め定義しておくと便利](https://zenn.dev/kaleidot725/articles/2022-02-20-jc-text-comopsable-list)

#### 使い方

- Android studioで「File > New > Activity > Empty Compose Activity」を選択するなどして、「`ComponentActivity`」を継承したActivityを作るなどする。
- `@Composable`マークのついた関数を作る。これによりレイアウトが作られる。
- `@Preview`マークをつければ、Android Studioでプレビューが即確認できるようになり大変便利である。
- `@RequiresOptIn`がついているマークがついているクラスを使いたい場合は、`@OptIn`
マークをつけて使う必要がある。
    - []()


[Android Compose のチュートリアル](https://developer.android.com/jetpack/compose/tutorial?hl=ja)

#### 子部品の配置を決定する際、親部品の配置を参考にしたい。

`BoxWithConstraints`を利用するとできる。

```kotlin:Home.kt
            BoxWithConstraints {
                print("maxHeight $maxHeight")
                inputArea(
                    height = maxHeight - bottomUpperHeight,
                )
            }
```

[Composeでのレイアウト - レスポンシブレイアウト](https://developer.android.com/jetpack/compose/layout?hl=ja#constraints)
[BoxWithConstraintsScope](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/BoxWithConstraintsScope)


### google/accompanist

Composeで正式に採用されていないような機能をComposeで使えるようにするという目的で実装された第三者ライブラリの集まり。https://github.com/google/accompanist
   - Compose側で正式採用されたことによって不要になるというケースもあるので情報を見ておこう。
   - 例： [`SwipeRefresh`](https://google.github.io/accompanist/swiperefresh/) -> [androidx.compose.material.pullrefresh](https://developer.android.com/reference/kotlin/androidx/compose/material/pullrefresh/package-summary)

#### アニメーション
コンポーザブルにおけるアニメーションの実現方法。

[Compose でのアニメーションのクイックガイド](https://developer.android.com/develop/ui/compose/animation/quick-guide?hl=ja)


#### ViewModel


[ViewModel の概要](https://developer.android.com/topic/libraries/architecture/viewmodel?hl=ja)




> Android アプリの場合、Activity や Fragment があり、これらに View があったり、ロジックがあったり、一時的なデータを保持したりしています。
> Activity や Fragment は、リソース確保や画面回転などにより、 Android フレームワークによって破棄されることがあります。そのときに、Activity や Fragment の内部で保持していたデータもいっしょに破棄されてしまいます。
> しかし、アプリ内部の一時的なデータを Activity や Fragment ではなくて ViewModel に持たせることで、Activity や Fragment が一時的に破棄されてしまっても、一時的なデータを保持し続けることができるようになります。

```groovy:build.gradle
dependencies {

    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
    implementation "androidx.activity:activity-ktx:1.4.0"
    implementation "androidx.fragment:fragment-ktx:1.4.1"
}

```

```
// by で ViewModel インスタンスを取得する。
val viewModel: MainViewModel by viewModels()

// ViewModelProvider で ViewModel インスタンスを取得する。
val viewModel = ViewModelProvider(this)[MainViewModel::class.java]

```
[【Android × Kotlin】ViewModel の基本的な使い方](https://tatsurotech.hatenablog.com/entry/android/viewmodel-basic)
[ViewModelコンポーネントの使い方編【Android Jetpack】](https://toronavi.com/jetpack-viewmodel)


#### LifeCycle Component

Activity, Fragmentはライフサイクルを持っているが、そこに直接いろいろなコードを書いていくとごちゃごちゃして肥大化していく。そこで、別のクラスからこれらのクラスのライフサイクルを参照してスッキリ書けるようにできるもの。

- [ライフサイクル対応コンポーネントによるライフサイクルへの対応 ](https://developer.android.com/topic/libraries/architecture/lifecycle?hl=ja)
- [Lifecycle](https://developer.android.com/jetpack/androidx/releases/lifecycle?hl=ja#groovy)
- [Lifecycleでライフサイクル対応コンポーネント作成](https://android.suzu-sd.com/2021/11/aac_lifecycle/)
- [新しく追加されたAACのLifecycleObserverを使ってAndroidのライフサイクルのコードをスッキリさせよう！](https://qiita.com/Pooh3Mobi/items/ef50b90098678eb5f476)
- [OnLifecycleEventより、DefaultLifecycleObserverを使おう](https://at-sushi.work/blog/22/)

- 例：
```kotlin:testLifeCycle
class MyObserver : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        connect()
    }

    override fun onPause(owner: LifecycleOwner) {
        disconnect()
    }
}

myLifecycleOwner.getLifecycle().addObserver(MyObserver())

```

#### LiveData


[LiveData の概要](https://developer.android.com/topic/libraries/architecture/livedata?hl=ja#transform_livedata)
[LiveDataコンポーネントの使い方編【Android Jetpack】](https://toronavi.com/jetpack-livedata)

ライフサイクルに応じて自動で購読破棄などができるデータ監視の仕組みである。

注意点はいろいろあるが、FragmentでObserveするときは、LifecycleOwner引数に対して自分自身（this）ではなく、viewLifeCycleOwnerを渡すこと。Fragmentのライフサイクルの状態が DESTROYED に変わるまでに、onCreateViewより後は複数回コールされる可能性があるため、前の監視が開放されずに残ってしまい、そのまま新しく監視が開始してしまう場合がある。

#### Navigation 

画面遷移を簡単にできるようにしたもの。

[10分で作る、Navigationによる画面遷移](https://qiita.com/tktktks10/items/7df56b4795d907a4cd31)

##### Composeと組み合わせて使用する場合


- 以下、引用
- NavControllerクラスインスタンスの作成

```kotlin:
val navController = rememberNavController()

```

- NavHostの作成

```kotlin:
NavHost(navController = navController, startDestination = "profile") {
    composable("profile") { Profile(/*...*/) }
    composable("friendslist") { FriendsList(/*...*/) }
    /*...*/
}

```

- 移動の実行

[`navigate()`](https://developer.android.com/reference/androidx/navigation/NavController#navigate(kotlin.String,androidx.navigation.NavOptions,androidx.navigation.Navigator.Extras))関数を用いる。

```kotlin:
navController.navigate("friendslist")

// Pop everything up to the "home" destination off the back stack before
// navigating to the "friendslist" destination
navController.navigate("friendslist") {
    popUpTo("home")
}

// Pop everything up to and including the "home" destination off
// the back stack before navigating to the "friendslist" destination
navController.navigate("friendslist") {
    popUpTo("home") { inclusive = true }
}

// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
    launchSingleTop = true
}
```
- 以上、引用　[Compose を使用したナビゲーション](https://developer.android.com/jetpack/compose/navigation?hl=ja) より

- その他の実装例: [compose-book-samples App.kt](https://github.com/usuiat/compose-book-samples/blob/main/Ch4_PracticalUiExample/app/src/main/java/net/engawapg/composebooksamples/practicaluiexample/App.kt)

## Android ViewBinding

xml上においてあるUI部品に、idで検索するというタイポがありうる形式ではなく、直接アクセスできるようにする機能。
公式 https://developer.android.com/topic/libraries/view-binding#kotlin
[【Android Studio】View Bindingの使い方（Kotlin編）](https://codeforfun.jp/android-studio-how-to-use-view-binding-with-kotlin/)

## Lyra
https://github.com/google/lyra

Googleが開発している、非常に小さい容量で高音質な音声データをエンコード・でコードできるコーデック。※ コーデックとは、映像や音声データをエンコード（符号化）／デコード（復号化）するプログラムのことです。https://www.stream.co.jp/blog/blogpost-13900/

## Logcat

Android Studio Dolphin　よりさらに便利に使えるようになった、ログを出すAndroid Studioの機能。https://zenn.dev/yumemi_inc/articles/2022-09-29-explalin-new-logcat

- `Log.e()`: エラーを出力
- `Log.w()`: 警告を出力
- `Log.i()`: 情報を出力
- `Log.d()`: 開発者向けの情報を出力。
- `Log.v()`: かなり細かい情報を出力。
- ログメッセージのほかタグ情報を渡せる。これは主にどのUI要素において発生したかを特定するために用いる。`MainActivity`など。

## Custom Chrome Tabs
ChromeなどのブラウザをAndroidアプリでアプリ内の画面のようにして出せる機能。

公式デモ　https://github.com/GoogleChrome/android-browser-helper/tree/main/demos/custom-tabs-example-app
解説　https://qiita.com/droibit/items/66704f96a602adec5a35

なお一般的にはwebコンテントを使うにはWebViewや、外部のブラウザを開くなどの方法がある。https://developer.android.com/develop/ui/views/layout/webapps


## Google Play In-App Review API

Google playでのレビューをお願いするウィンドウをAndroidアプリ内で表示させることが出来ます。実装方法はシンプルですが、動作確認のほうがめんどくさいとのこと。

https://iridge-tech.hatenablog.com/entry/2022/10/24/143112


## Activity

[アクティビティの概要](https://developer.android.com/guide/components/activities/intro-activities)

- iOSでいうViewController
- main() メソッドで起動するアプリをプログラミングする際の枠組みとは異なり、1 つのアプリが別のアプリを呼び出すとき、呼び出し元のアプリは、別のアプリ全体をひとまとめとして呼び出すのではなく、その中のアクティビティを呼び出す。
- アクティビティの実装は Activity クラスのサブクラスとして行う。
- アクティビティにより、アプリが UI を描画するウィンドウが用意される。通常、このウィンドウは画面全体に表示されますが、画面よりも小さく、他のウィンドウの上に重なることもある。
- アクティビティをアプリで使用するには、アプリのマニフェストにその情報を登録する必要がある。
- [インテント フィルタ](https://developer.android.com/guide/components/activities/intro-activities#dif): 明示的なリクエストだけでなく、暗黙的なリクエストに基づいてアクティビティを起動する機能。この機能を使用するには、<activity> 要素の中の <intent-filter> 属性を宣言する。
- ライフサイクルは、onCreate()、onStart()などがある。

## Adapter

[Android Developers - Adapter](https://developer.android.com/reference/android/widget/Adapter)
[Android Developers - AdapterView](https://developer.android.com/reference/android/widget/AdapterView)
[アンドロイド　アプリ開発講座 - アンドロイド Adapter について](https://sites.google.com/site/androidsoftfh/99-android-adapter-nitsuite)
[Androidのお勉強 第二回 ListViewと独自Adapterについて](https://qiita.com/yu_eguchi/items/65311af1c9fc0bff0cb0)

- ListView, GridView, Spinner, Gallery など、AdapterViewを継承クラスする画面部品のクラスを使う際に、それらのクラスに渡すものとしてAdapterが必要となる。
- UI部品とデータソースを仲立ちする役目を持っている。
- Android公式で用意しているAdapterクラスをそのまま使っても良いし、自分でAdapterを継承してクラスを作っても良い。

## Contract

[Medium - Model-View-Presenter: Android guidelines](https://medium.com/@cervonefrancesco/model-view-presenter-android-guidelines-94970b430ddf)
[Android Architecture Blueprints](https://github.com/android/architecture-samples)

- View, Presenterのインターフェースをまとめて記載しておく場所。


## API Level, SDK Versionの関係
[Android SDK API Level 一覧](https://qiita.com/irgaly/items/bd2ffe3725424690b856)

## 画像、文字列などのリソース

通常、`/res`フォルダ内にさまざまなサブフォルダを作り、その中に配置することとなっている。どのようなサブフォルダにどのようなリソースを置くかは、下記参照。

[アプリのリソースの概要](https://developer.android.com/guide/topics/resources/providing-resources?hl=ja)

新規のリソース(xmlファイル)はandroid studioの[File] > [New] > [Android resource file]で追加できる。

参照: [アプリのリソースを追加する](https://developer.android.com/studio/write/add-resources?hl=ja)
[ベクター型ドローアブルの概要](https://developer.android.com/guide/topics/graphics/vector-drawable-resources?hl=ja)

### フォント

res/fontフォルダ以下に配置することとなる。.ttfファイルや、.xmlファイルを置ける。

[XML フォント](https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml?hl=ja)


### アプリアイコン(mipmap)

mipmapフォルダにアプリアイコンを配置できます。

[各種のピクセル密度をサポートする](https://developer.android.com/training/multiscreen/screendensities?hl=ja#mipmap)

### スタイル・テーマ

[スタイル・テーマ](https://developer.android.com/guide/topics/ui/look-and-feel/themes?hl=ja)


## Room

SQLiteをAndroidで扱うためのライブラリである。

[【Android】はじめてのRoom](https://qiita.com/iTakahiro/items/7e0d63140ae4dac10d18)
[Google Developers - Room](https://developer.android.com/jetpack/androidx/releases/room?hl=ja)
[github - iTakahiro/ArchitectureFootball](https://github.com/iTakahiro/ArchitectureFootball/blob/master/app/build.gradle)

## DataStore

Jetpackを使っている場合で、データベースに入れるまでもないちょっとしたデータを保存したい場合は[DataStore](https://developer.android.com/topic/libraries/architecture/datastore?hl=ja)を使うと良い。

上記のリンクは公式ドキュメントであるが,Proto DatastoreについてProtobufというライブラリが必要なのにそのことが書いていないので、むしろ[このCodeLab](https://developer.android.com/codelabs/android-proto-datastore?hl=ja#4)を見たほうが良いと思われる。

なおJetpackを使っていない場合は[SharedPreference](https://developer.android.com/training/data-storage/shared-preferences?hl=ja)を利用する。

## 既存のスプラッシュ画面の実装を Android 12 以降に移行する
[既存のスプラッシュ画面の実装を Android 12 以降に移行する](https://developer.android.com/guide/topics/ui/splash-screen/migrate?hl=ja#kotlin)
アンドロイド12以降では、アプリの最初のスプラッシュ画面をシステムが用意したものに置き換える必要がある模様。

## Kotlin Coroutine

（メイン）スレッドをブロックすることなく、並行処理・非同期処理を行うための仕組み。

- [Android での Kotlin コルーチン](https://developer.android.com/kotlin/coroutines?hl=ja)
- [Android での Kotlin Flow](https://developer.android.com/kotlin/flow?hl=ja)
- [公式ドキュメント](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)
- [Kotlin の Coroutine で suspend 関数を理解する](https://qiita.com/duke105/items/b5be074c79c6bed4d560)
- [初学者向けKotlin Coroutines Flow](https://qiita.com/tonionagauzzi/items/12aa1a4400256cece72c)
- [Coroutines Flow で ジェネリック ズンドコキヨシ](https://qiita.com/aMasatoYui/items/60057f51d6e444231f96)

### チートシート

- 以下、引用

![スクリーンショット 2023-03-13 20.48.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/579e95e9-a428-8a19-95f3-ec98079f6ec3.png)

- 以上、引用 [Kotlin Flows ~ an Android cheat sheet](https://rvbsoftdev.medium.com/kotlin-flows-an-android-cheat-sheet-d71ae772030d)より
    - おおむね以下のような構成となっているようである。
    - [`Flow`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/): 非同期データストリームで、正常終了またはエラー付き終了を行う。
    - [`SharedFlow`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-shared-flow/): Flowを継承したもの。一つのデータフローを複数のサブスクライバーの間で購読するので、複数から購読されても一つのフローしか走らない。任意の数のリプレイキャッシュを持つ。
    - [`MutableSharedFlow`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-mutable-shared-flow/): `SharedFlow`を継承したもので、値をフローに流すための関数も持つ。
    - [`StateFlow`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/): `SharedFlow`を継承したもの。必ず初期値を持つ。リプレイ用のキャッシュの数は強制的に1個のみとなる。購読をせずに最新の値を取得する機能も持つ。
    - [`MutableStateFlow`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-mutable-state-flow/): `StateFlow`を継承したもので、値をフローに流すための関数も持つ。

- [Kotlin Coroutines Cheat Sheet](https://dev.to/touchlab/kotlin-coroutines-cheat-sheet-5872)

- [ARE KOTLIN COROUTINES ENOUGH TO REPLACE RXJAVA?](https://www.javaadvent.com/2021/12/are-kotlin-coroutines-enough-to-replace-rxjava.html): RxJava と kotlin croutineの対照表。


### オペレータ

- 一覧
    -[Flow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)

- マーブルダイアグラム（そのオペレータに値を流したらどうなるかを図にしたもの）
    - [Flow Marbles: Interactive diagram of Kotlin Flow](https://flowmarbles.com)

- [`onStart`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-start.html)
    - FlowがCollectを開始する前に呼ばれる

- [`stateIn`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/state-in.html)
    - coldである「Flow」をhotである「StateFlow」に変換することができる。

### その他

- `Backpressure`: RxJavaで使われていた用語のようで、パブリッシャーの出すイベントが多すぎる時などにサブスクライバが処理できるようにフィルタリングしたりするオペレータのことを指す。
    - [RxJava Backpressure](https://medium.com/@srinuraop/rxjava-backpressure-3376130e76c1)

## Fragmentとは

使い回しができるUI部品である。
[Android Developers - フラグメント](https://developer.android.com/guide/fragments)
[Android はじめてのFragment](https://qiita.com/Reyurnible/items/dffd70144da213e1208b)

## Dagger

DIが便利にできる機能。
[Android Developers - Dagger の基本](https://developer.android.com/training/dependency-injection/dagger-basics)
[github - Dagger](https://github.com/google/dagger)
[Dagger - Documentation](https://dagger.dev)

[【Android】はじめてのDagger2](https://qiita.com/iTakahiro/items/c9203f5ad886b7ddae2f)
[Dagger 2 Tutorial For Android: Advanced](https://www.kodeco.com/6583167-dagger-2-tutorial-for-android-advanced)



### @Inject マーク

これをコンストラクタの前につけることで、どのように該当クラスを初期化すべきなのかDaggerに知らせることができる。

メンバ変数の前につけるやり方もあるが、その場合は@Component を用いる必要がある。


### @Component マーク

これをインターフェース、宣言の前につけることで、公開する型が満たす必要がある依存関係をすべて持ったコンテナの生成を指示する。このコンテナを見ることで、repositoryなど各クラスに必要なクラスのオブジェクトが準備される。

具体的には、@ComponentをつけたHogehogeComponentというのを作ったのであれば、自動的に「DaggerHogehogeComponent」というクラスが生成され、そこからさまざまなクラスをbuild()メソッドで作っていくことができる。


### @Provides マーク

@InjectではInterfaceは初期化できない・サードパーティのクラスは初期化できない・初期化時に設定が必要なものを設定できないことがあるため、そういう時に代わりに使用する。

### @Bindsマーク

@Providesにおいて、インターフェースにマークをつける時、ただ特定のクラスを実装として返したいというだけの場合は、代わりに@Bindsマークをつけることが推奨されている。

@Bindsと@Providesが両方あるModuleは普通は作れないので、別に一個モジュールを作るか、どうしてもモジュールを一個だけにしたい場合はcompanion objectと@JVMStatic というマークを利用した書き方をする必要がある。詳しくは:

[Using @Binds](https://www.kodeco.com/6583167-dagger-2-tutorial-for-android-advanced#toc-anchor-011)



### @Moduleマーク

@Provides, @Bindsは全て@Moduleマークのついた括弧内に収まる必要がある。

### @Singletonマーク

@Providesと一緒につけることでシングルトンオブジェクト化する + Applicationクラスをカスタマイズする必要がある。詳しくは下記参照。
[Providing Singleton Values](https://www.kodeco.com/6583167-dagger-2-tutorial-for-android-advanced#toc-anchor-008)

### Dagger2 Android拡張

- Android向けにDagger2をさらに便利に描けるようにできる機能。

[Dagger2のAndroidサポートが何をしているのか理解する](https://qiita.com/ko2ic/items/35d077499734bfd777fc)


> しかし、Android拡張を使って以下の手順を行うと、上記の定型的なコードを書く必要がなくなります。
ApplicationComponentの@Component.modulesにAndroidSupportInjectionModuleを追加する。
ActivityBindingModuleを作成し、ApplicationComponentの@Component.modulesに設定する。
ActivityBindingModuleでは、Member Injectionの対象となるActivityを戻り値とした引数なしメソッドを宣言する。そのメソッドには、@ContributeAndroidInjectorを付与する。これにより、ActivityにMember InjectionするためのSubComponent(=AndroidInjector<対象のActivity>)とAndroidInjector<対象のActivity>.Factoryが自動生成される。このAndroidInjector<対象のActivity>.Factoryは1.のAndroidSupportInjectionModule(厳密にはそれが保持している AndroidInjectionModule)のMap<Class, AndroidInjector.Factory>にActivityのクラス名をキーとしてMultiBindingされる。
ActivityでDaggerAppCompatActivityを継承する。
これにより、Activityは以下のように振る舞います。
ActivityのonCreateでベースクラスDaggerAppCompatActivityのAndroidInjection.inject(this)が実行される。
AndroidInjection.inject(this)で、Applicationが保持しているDispatchingAndroidInjector のinject(this)が実行される。
DispatchingAndroidInjector.injectでは、AndroidInjectionModuleによりDispatchingAndroidInjectorにInjectされたMap<Class, AndroidInjector.Factory>から、ActivityのAndroidInjector.Factoryを取得する。
取得したAndroidInjector.FactoryからActivityのAndroidInjectorを生成し、AndroidInjector.injectを呼び出し、ActivityにMember Injectionする。

[Android Architecture BlueprintsでDagger2のAndroid拡張を理解する](https://qiita.com/yuki_m/items/91d31857e54adcf32545)

#### DaggerAppCompatActivity

- Android拡張を利用する際は、自分で作ったActivityをこの[DaggerAppCompatActivity](https://dagger.dev/api/2.13/dagger/android/support/DaggerAppCompatActivity.html)を継承させる必要がある。


## Hilt

Daggerの上に構築されたDIライブラリ。Hiltとは剣のつかの意。Daggerにはないアノテーションマークがある。

[Hiltを使ってViewModelに依存性を注入(DI)する](https://tech.mokelab.com/android/compose/app/hilt/viewModel.html)

公式ドキュメントは以下
[Hilt を使用した依存関係の注入](https://developer.android.com/training/dependency-injection/hilt-android?hl=ja#component-hierarchy)
[Dependency injection with Hilt](https://developer.android.com/training/dependency-injection/hilt-android#generated-components)


### @HiltAndroidApp マーク

Hiltを使う場合は、「Application」を継承するクラスを作り、「@HiltAndroidApp」をつける必要がある。

###  @HiltViewModel マーク

ViewModelの宣言部分に@HiltViewModel マークをつける。コンストラクタには@Injectをつける。

### hiltViewModel()

ViewModel初期化時には`hiltViewModel()`を使う。





## Springboot + kotlin

kotlinでwebアプリケーションを作るときによく使うDIフレームワークだそうだが、AndroidアプリのGoogleの公式実装例で使われていたので軽く参考サイトを記載するにとどめる。

[【Springboot / Kotlin】アノテーションを学ぶ（DI系）](https://zenn.dev/tm35/articles/101df54b9e32a7#%40component)
[Spring BootでサーバーサイドKotlin入門](https://qiita.com/kawasaki_dev/items/1a188878eb6928880256)
[Spring Boot + Kotlin で依存性を注入する](https://nbtk.hatenablog.com/entry/2021/12/17/125806)

## @StringRes, @DrawableRes などアノテーションによるコード検査

Android開発において文字列、画像などのリソースにアクセスする際、int型のIDを使ってアクセスする。しかしただのint型なので、間違った値を渡してしまい、クラッシュするなどの危険がある。これを避けるため、`androidx.annotation`というパッケージが用意されており、文字列、画像などリソースの種類に応じたアノテーションをつけることで間違いを避けることができる。

他の Jetpack ライブラリを使用している場合は、androidx.annotation の依存関係を追加しなくてもアクセスできる場合がある。

[アノテーションによるコード検査の改善](https://developer.android.com/studio/write/annotations?hl=ja#adding-annotations)

- 以下、引用

| アノテーション | リソース ID の種類 |
|:-----------|:------------|
| @AnimatorRes       | R.animator.xxx で参照するリソース ID        |
| @AnimRes	       | R.anim.xxx で参照するリソース ID        |
| @AnyRes	       | いずれかの種類のリソースの ID（他の具体的なアノテーションを使用することを推奨）        |
| @ArrayRes	      | R.array.xxx で参照するリソース ID        |
| @AttrRes	      | R.attr.xxx で参照するリソース ID       |
| @ColorRes	     | R.color.xxx で参照するリソース ID        |
| @DimenRes	      | R.dimen.xxx で参照するリソース ID     |
| @DrawableRes	      | R.drawable.xxx で参照するリソース ID        |
| @FontRes	     | R.font.xxx で参照するリソース ID        |
| @IdRes	      | R.id.xxx で参照するリソース ID      |
| @InterpolatorRes	 | R.interpolator.xxx で参照するリソース ID   |
| @LayoutRes	      | R.layout.xxx で参照するリソース ID  |
| @NavigationRes	    | R.navigation.xxx で参照するリソース ID        |
| @RawRes	   | R.raw.xxx で参照するリソース ID       |
| @StringRes	   | R.string.xxx で参照するリソース ID       |
| @StyleableRes	     | R.styleable.xxx で参照するリソース ID       |
| @StyleRes	      | R.style.xxx で参照するリソース ID        |
| @TransitionRes	     | R.transition.xxx で参照するリソース ID   |

- 以上、引用 [リソース ID を示す変数やパラメータにアノテーションを付ける](https://maku77.github.io/android/fw/res-annotation.html)









## RecyclerView

iOSで言ったらTableView, CollectionView的なもので、 パフォーマンスへの影響を最小限に抑えながら、動的なリストを作成できる。ViewHolder, Adapterというクラスを一緒に使用する。

[RecyclerView で動的リストを作成する](https://developer.android.com/guide/topics/ui/layout/recyclerview?hl=ja#kotlin)
[Recyclerview](https://developer.android.com/jetpack/androidx/releases/recyclerview#kts)
[RecyclerViewの基本](https://qiita.com/naoi/items/f8a19d6278147e98bbc2)


## RxKotlin, RxJava
リアクティブプログラミングが可能。は[RxJava](https://github.com/ReactiveX/RxJava)は[RxKotlin](https://github.com/ReactiveX/RxKotlin)を使いやすくしたものなので、前者の方がドキュメント・情報は多そう。

[Rxで知っておくと便利なSubjectたち](https://qiita.com/ralph/items/f7205c8171826cc2153b)
[【Android / Kotlin】Rx を理解する（ストリーム編）](https://qiita.com/tkmd35/items/24a62250e772dbfc873c)
[RxKotlin入門を目指してRxについて知る](https://qiita.com/a_yoshio/items/f81be1b28d65fd7cf9ae)

### CompositeDisposable

複数のDisposableを集めておき、一気に好きなタイミングでdisposeできる。
[RxJava - Using CompositeDisposable](https://www.tutorialspoint.com/rxjava/rxjava_compositedisposable.htm)




## app/build.gradleにフレーバー毎の定数を用意する

可能である。


```
    /**
     * The defaultConfig block encapsulates default settings and entries for all
     * build variants, and can override some attributes in main/AndroidManifest.xml
     * dynamically from the build system. You can configure product flavors to override
     * these values for different versions of your app.
     */
```
-> defaultConfigブロックで設定したものがデフォルトの値となる。
```
    /**
     * The productFlavors block is where you can configure multiple product flavors.
     * This allows you to create different versions of your app that can
     * override the defaultConfig block with their own settings. Product flavors
     * are optional, and the build system does not create them by default.
     *
     * This example creates a free and paid product flavor. Each product flavor
     * then specifies its own application ID, so that they can exist on the Google
     * Play Store, or an Android device, simultaneously.
     *
     * If you declare product flavors, you must also declare flavor dimensions
     * and assign each flavor to a flavor dimension.
     */
```
-> productFlavorブロックに書いた、各フレーバー用の設定で上書きできる。
[ビルドを設定する](https://developer.android.com/studio/build#kts)より


```
android {

 ...

 buildTypes {
 debug {
 ...

 resValue "string", "GOOGLE_MAPS_ANDROID_API_KEY", "(your development Maps API key)"
 }
 release {
 ...

 resValue "string", "GOOGLE_MAPS_ANDROID_API_KEY", "(your production Maps API key)"
 }
 }
}

```

```
import com.yourpackage.name.BuildConfig;

private void doSomethingWithUrlEndpoint() {
 String urlEndpoint = BuildConfig.URL_ENDPOINT;

 ...
}

```
[Using String Constants Generated by Gradle Build Configurations](https://michiganlabs.com/news/string-constants-generated-gradle-build-configurations)より

- buildType(debug, releaseなど)およびflavorDimensions(buildTypeよりさらに細かい設定分け)の組み合わせで、さらに柔軟なフレーバーの作成が可能である。
- 以下、引用

> 最後のパターン、プロダクトフレーバーのdimensionが複数ある場合です。
そんな複雑な構成は実務で生じるのか、と疑問に思うかもしれませんが、今回この記事を書くに至った理由が、実際のプロジェクトの現場でこの構成のビルドが必要になったためでした。

> 当該のプロジェクトではプロダクトフレーバーを用いて開発、ステージング、本番環境ごとのアプリを作成していました。
そこに、アプリで扱う商品のブランドごとにバージョン管理したいと言う要件が生じたため、さらにブランドのdimensionを追加してバージョン管理していました。

> 今回の検証では、color dimensionを追加して、色ごとにバージョン管理できるように設定してみます。
> build.gradleファイルは抜粋すると以下のようになっています。

```groovy:build.gradle
apply plugin: 'com.android.application'

android {
    //省略...

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }
    }

    flavorDimensions "plan", "color"
    productFlavors {
        paid {
            dimension "plan"
        }
        free {
            dimension "plan"
        }
        purple {
            dimension "color"
        }
        green {
            dimension "color"
        }
        red {
            dimension "color"
        }
    }

}

```

> このようにflavorDimensionsはカンマで区切ることで複数定義できます。
さて、これをビルドすると… だんだん複雑になってきましたが、ビルドタイプ × プロダクトフレーバー(plan) × プロダクトフレーバー(color) の組み合わせで12通りのビルドバリアントが作成されました。

- 以上、引用 [Androidのビルドバリアントをイチから理解する](https://future-architect.github.io/articles/20210120/)より




## build.gradle, settings.gradle, gradle.properties の使い分け

- `build.gradle`: Groovyファイルである。デフォルトで存在している、基本となる設定ファイル。各モジュールに適用される設定を記載する(Module:app)と、プロジェクト全体に適用される(Project:app)がある。
    - `Module:app`
        - `apply plugin: 'com.android.application'`: Androidアプリ用のビルドであることを示す一文。
        - `android {}` ブロック: android のビルドにおける設定を記載する。典型的には`compileSdkVersion` `buildToolsVersion`など。
            - `defaultConfig`ブロックにおいては、debug, releaseといった各ビルド設定全部に共通する設定を記載する。
            - `buildTypes`ブロックにおいては、debug, releaseといったビルド設定のうち、特定のビルド設定にのみ通用する設定を記載する。
        - `dependencies {}` ブロック: アプリが実行時に利用するライブラリを記載する。
    - `Project:app`
        - `buildscript{}` ブロック: ビルドツールに関する設定を記載する。
        - `allprojects{}` ブロック: 全プロジェクトで共通する設定を記載する。
   - [What is the Gradle Scripts folder in an Android project? What is the difference between build.gradle(Module: app) and build.gradle(Project: app)? In-depth and simple explanation.](https://blog.devgenius.io/what-is-the-gradle-scripts-folder-in-an-android-project-c4b019ea95e0)

- `settings.gradle`: Groovyファイルである。複数のモジュールがあるマルチプロジェクトにする時に用いる。どういったモジュールを使うのかを指定できる。一つのモジュールしかない時は、`include ':app'` などといった記述が1行だけで終わるが、複数モジュールを使うときはもっと記述が増えていく感じである。
   - [Gradle: build.gradle vs. settings.gradle vs. gradle.properties](https://www.baeldung.com/gradle-build-settings-properties)
   - [Gradleでマルチプロジェクト](https://qiita.com/shiena/items/371fe817c8fb6be2bb1e)

- `gradle.properties`: デフォルトでは存在しない。ビルドの過程においての設定を記載するためのファイル。  -Dgradle.user.home コマンドラインで指定した場所、GRADLE_USER_HOME, プロジェクトルート などにおくことができ、この順の優先順位で適応される。例えば、機密情報を直接build.gradleに書きたくないのでここに書いておいたり、環境ごとに違う設定値を適用したいのでここに書いておいたりということができる。key=value形式で記載していく。この値はコマンドラインから指定することもできる。最終的な優先順位は以下のようになる。以下、引用
   - コマンドラインで`./gradlew <task-name> -PmyPropName1=myPropValue1 -PmyPropName2=myPropValue2`のように指定したもの
   - Javaシステムプロパティで以下のように指定したもの: `./gradlew <task-name> -Dorg.gradle.project.myPropName1=myPropValue1 -Dorg.gradle.project.myPropName2=myPropValue2`
   - 環境変数で以下のように指定したもの: `ORG_GRADLE_PROJECT_myPropName1=myPropValue1 ORG_GRADLE_PROJECT_myPropName2=myPropValue2 ./gradlew publish`
   - `GRADLE_USER_HOME`ディレクトリ(通常は`~/.gradle/gradle.properties`)に置いてあるgradle.propertiesに書いてある値
   - プロジェクトルートにおいてあるgradle.propertiesに書いてある値
   - 以上、引用:  [Gradle Project Properties Best Practices](https://tomgregory.com/gradle-project-properties-best-practices/)
   - 参考: [Build Environment](https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties)

## build.gradle

### 総論


Groovyという、Javaを元にした言語で書かれているファイルで、Androidのビルドの設定などを記述できる。

Groovyはシンタックスシュガーが多く、一見しただけでは何故これで動いているのかよくわからないなどという事態が発生しがちなので、ある程度学んでおくと良い。

[Gradle (build.gradle) 読み書き入門](https://qiita.com/hatimiti/items/a127311d739c9d3e0045#追加したプロパティを利用してみる)
[Gradle User Manual](https://docs.gradle.org/current/userguide/userguide.html)
[Android Studio の Gradle の備忘録](https://qiita.com/izuki_y/items/5de57db9acb3b24cb77e)
[Groovyを知らない人のためのbuild.gradle読み書き入門](https://qiita.com/opengl-8080/items/a0bb31fb20cb6505188b)
[Gradleビルド言語リファレンス](http://gradle.monochromeroad.com/docs/dsl/index.html)
[Android Gradle plugin API reference](https://developer.android.com/reference/tools/gradle-api)

### 各論

#### [apply plugin](https://docs.gradle.org/current/javadoc/org/gradle/api/Plugin.html#apply-T-)

Project レベルbuild.gradleにて、apply関数（plugin は引数）を呼ぶことで、特定のライブラリをそのプロジェクトに適用させることが可能。[Using plugins](https://docs.gradle.org/current/userguide/plugins.html#sec:using_plugins)





- `apply plugin: 'com.android.application'`
    - Androidで開発する時は大体核と思われる。AAB対応後に役割が変わっている。[Android App Bundle に対応できるように Instant App を移行する](https://developer.android.com/topic/google-play-instant/feature-module-migration?hl=ja)
- `plugins {
    id 'kotlin-android'
}`
    - kotlin言語を使ってアプリを作るときに記述するもの。[Kotlin を既存のアプリに追加する](https://developer.android.com/kotlin/add-kotlin)

- `apply plugin: 'kotlin-kapt'`
    - kaptというライブラリをkotolinで使うとき必要。kaptによりkotolinでも@などを使ったアノテーションを使えるようになる。Daggerなどのツールを使うときに必要。
    - [kaptのセットアップ方法&使い方](https://qiita.com/uhooi/items/836902cdd322f9accded)

- `apply plugin: 'kotlin-android-extensions'`
    - Kotlin Android Extensions を使うために必要な記述・・・だが、これはすでにdeprecatedとなっており、代わりにViewBindingを使うことが推奨されている。
    - [Kotlin Android Extensions から View Binding に置き換える](https://zenn.dev/kmd_htsh0226/articles/91ef3b833b6c0f)
    - [Migrate from Kotlin synthetics to Jetpack view binding](https://developer.android.com/topic/libraries/view-binding/migration)

#### [`buildscript`](https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies), [`plugin`](https://docs.gradle.org/current/userguide/plugins.html#sec:constrained_syntax), [`depdendencies`](https://docs.gradle.org/current/userguide/declaring_dependencies.html#sub:config-inheritance-composition)

> プロダクトコードではなく、ビルドスクリプト( build.gradle )内で利用するプラグインや依存関係の定義については buildscript に定義します。
OSSなどを利用する場合は、プロダクトコード同様に repositories と dependencies に定義します。 

[Gradle (build.gradle) 読み書き入門](https://qiita.com/hatimiti/items/a127311d739c9d3e0045#buildscript-プロパティ) より

- ライブラリをインストールするものとして`buildscript`と`plugin`と`dependencies`（`buildscript`のカッコ内にある`dependencies`とはまた別のもの）の三つがある。
   - `buildscript`は、上述の通りbuild.gradle内で使いたいライブラリをインストールするために使用する。
   - `plugin`も同様の機能を持つが、`plugin`の方が新しくできた機能で簡単にできるため、ライブラリが対応していればこちらを使った方が良い。

- 以下、引用

```groovy:build.gradle
//pluginsの使用例

// 可能な限りファイルの最初の方で定義
plugins {
    id 'checkstyle'
}


//buildscriptの使用例

// 可能な限りファイルの最初の方で定義
buildscript {
    repositories {
        mavenCentral()
    }

    // buildscript内で使用するdependenciesは、あくまでbuildscript内で効力を持つものであり、
    // 通常のdependenciesの様にアプリケーションコード内で使用できるようにはならない
    dependencies {
        classpath platform('software.amazon.awssdk:bom:2.17.160')
        classpath 'software.amazon.awssdk:s3'
    }
}

```

- 以上、[build.gradleのbuildscript、plugins、dependenciesの違いについて](https://tech.excite.co.jp/entry/2022/08/15/153626)より引用

- `dependencies`は、アプリ内で使うライブラリをインストールする時に使う。
   - 以下、引用
```groovy:build.gradle
allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    // 必要になる部分で定義
    dependencies {
        implementation "org.apache.httpcomponents:httpclient:4.5.13"
    }
}

```

   - 以上、[build.gradleのbuildscript、plugins、dependenciesの違いについて](https://tech.excite.co.jp/entry/2022/08/15/153626)より引用



#### `repositories { google() mavenCentral() }`


    ライブラリのダウンロード元として、オープンソースライブラリ集として有名なmaven central(主にJavaライブラリ)とGoogle(主にAndroid専用ライブラリ)を指定する。これを、buildscriptの中に記載する。[Declaring repositories](https://docs.gradle.org/current/userguide/declaring_repositories.html)





#### `buildconfig`
    - `buildConfigField`にさまざまな値を定義してあげることで、環境ごとの値を定義し、別の場所で（プロダクトコード上からも）参照できる。
    - [カスタム フィールドとリソース値をアプリのコードと共有する](https://developer.android.com/studio/build/gradle-tips?hl=ja#share-custom-fields-and-resource-values-with-your-app-code)
    - `root/build.gradle`　で以下のように具体的な値を定義してあげると、`module/build.gradle`で使いやすい。

```groovy:root/build.gradle
buildscript {

  ext.buildConfig = [
      compileSdk: 10,
      buildTools: "29.0.3",
      minSdk: 25,
      targetSdk: 10,
      versionCode: 200,
      versionName: "2.9.0",
      multiDex: true
  ]

  ext.versions = [
      android: [
          appcompat: '1.0.0',
          ktx: '1.3.0',
          constraintlayout: '1.1.9',
          recyclerview: '1.3.0',
          design: '1.2.0'
      ],
      kotlin: '1.5.32',
      lifecycle: '2.3.0',
      retrofit: '2.6.0',
      moshi: '1.2.0',
      kotshi: '2.4.3',
    ]

```

```groovy:module/build.gradle
android {

  compileSdkVersion buildConfig.compileSdk

  defaultConfig {

    minSdkVersion buildConfig.minSdk
    targetSdkVersion buildConfig.targetSdk

    versionCode buildConfig.versionCode
    versionName buildConfig.versionName

  }
}

```

#### `compileSdkVersion`, `minSdkVersion`, `targetSdkVersion`の区別


- compileSdkVersion: コンパイルに使うSDKバージョン。新しい機能を使えるようにするため、基本的には現時点での最新を指定する。
    - minSdkVersion: アプリの最低OSバージョン。古いOSをサポートする場合、こちらの値を小さくする。
    - targetSdkVersion: アプリを動作させるAPIレベルを指定。compileSdk と同じく基本的には現時点での最新を指定すればいい。例えばAndroid 12（APIレベル 31 ）対応が完了していない場合、 targetSdk を 30 に指定すればAndroid 12でも11のように振る舞う。

    - [基本をおさえる！Androidアプリで指定するバージョンについて(compileSdk,buildToolsVersion,....)](https://qiita.com/takahirom/items/e00126586c13aebf1a6b#compilesdkversion)
    - [compileSdk・minSdk・targetSdkの違い(Android)](https://qiita.com/uhooi/items/0f2ad61d83b96d9166c8)
    - [compileSdkVersion, targetSdkVersion区别](https://blog.csdn.net/qq_33413264/article/details/87860775)


#### defaultConfig
- 全てのビルドフレーバー間で共通する設定を記載できるブロック。[ビルドを設定する](https://developer.android.com/studio/build#module-level)
    - defaultConfigブロックで記載した設定は、各フレーバーでの設定を記載するproductFlavorsブロックでアクセスできる。　[プロダクト フレーバーの設定](https://developer.android.com/studio/build/build-variants#product-flavors)

- `testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"`
    -  最初から記載されている記述。インストゥルメント化テスト（UIテスト）のためJUnit4テストクラスを利用するとの意味である。[インストゥルメント化単体テストを作成する](https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests?hl=ja)

#### archivesBaseName
- AABを生成する場合に、最終的な生成ファイル名を変えることができる。指定しない場合は、プロジェクトの名前がそのまま使われることとなる。
        - [Gradle Javaプラグイン - 生成されるjarファイルの名前](https://www.ne.jp/asahi/hishidama/home/tech/groovy/gradle/java.html)
        - [【Android】生成するapk/aabのファイル名にバージョン名や実行日時を入れる](https://www.memory-lovers.blog/entry/2020/03/17/110000)

#### `buildConfigField` vs `resValue`
- 両方、環境ごとの設定項目を設定するのに使える。前者の値はランタイムにプログラムからアクセスできる。後者の値も同様だが、アプリの`res`フォルダに追加される。
        - [What's the difference between buildConfigField, resValue and manifestPlaceholders?](https://stackoverflow.com/questions/42725299/whats-the-difference-between-buildconfigfield-resvalue-and-manifestplaceholder)

#### `sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8`
- Androidの最小APIレベルを低めに設定している場合、でも、Java 8 言語機能を使うための設定。
        - [Java 8+ API の desugar のサポート（Android Gradle プラグイン 4.0.0+）](https://developer.android.com/studio/write/java8-support#library-desugaring)
        - [古めのAndroidバージョンをサポートしたままJava 8+ APIを使う方法](https://suihan74.github.io/posts/2021/02_08_00_core_library_desugaring/)

#### `kotlinOptions` `jvmTarget = '1.8'`
- 上と同じくJava8対応だが、kotolinを使っているプロジェクトではこれが必要な模様。
        - [Java 8 言語機能のサポート（Android Gradle プラグイン 3.0.0+）](https://developer.android.com/studio/write/java8-support?hl=ja#supported_features)
        - [一部のktxを使うにはJava8対応が必要](https://qiita.com/nichiyoshi/items/39e84abe68a34eb424cf)

#### `dependencies` `implementation`
- ライブラリを追加するための記述。
    - [ビルド依存関係を追加する - 依存関係のタイプ](https://developer.android.com/studio/build/dependencies#dependency-types)
    - [Gradle の compile, api, implementation とかについて](https://qiita.com/opengl-8080/items/6ad642e0b016465891de)
    - `implementation project(':mylibrary')`
        - ローカルにあるモジュールを参照する時。
    - `implementation fileTree(dir: 'libs', include: ['*.jar'])`
        - ローカルにあるバイナリ（ここではjarファイル）を参照する時。
    - `  implementation 'com.example.android:app-magic:12.3'`
        - リモートにあるバイナリを参照する時。
  
#### `allprojects`, `subprojects`, `project(":HogeProject")`
- Gradleを使う場合、通常一つのルートプロジェクトと、その配下の一つ又は複数のサブプロジェクトという構造となっている。
    - `allprojects { ... }`という書き方をすると、括弧内で書いたことを全プロジェクトに適用できる。
    - `subprojects　{ ... }`という書き方をすると、括弧内で書いたことを全サブプロジェクトに適用できる。
    - `project(":HogeProject") { ... }`という書き方をすると、括弧内で書いたことを特定プロジェクトに適用できる。
    - [Structuring and Building a Software Component with Gradle](https://docs.gradle.org/current/userguide/multi_project_builds.html#sec:dependencies_which_dependencies)
    - [KtLint + Spotless + GitHub ActionsでPRにsuggested changeさせる](https://qiita.com/takahirom/items/2a3d2912e74107748765)

#### Java, Kotlin コンパイルオプションの書き方

- 以下のように記載する。以下、引用

```groovy:build.gradle
allprojects {
    gradle.projectsEvaluated {

        // Javaコンパイル時
        tasks.withType(JavaCompile) {
            options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
        }

        // Kotlinコンパイル時
        tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
            kotlinOptions {
                freeCompilerArgs = [
                        "-Xjavac-arguments='-Xlint:unchecked -Xlint:deprecation'"
                ]
            }
        }
    }
}

```

- 以上、引用([AndroidアプリのJava/Kotlinコンパイル時オプションを指定する](https://qiita.com/temoki/items/0f75c74c51fe6e6a036a))

- Googleの公式サンプルアプリ Architecture Samples では以下のようにkotlin optionを指定していた。
```groovy:build.gradle
subprojects {
    tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
        kotlinOptions {
            freeCompilerArgs += '-opt-in=kotlin.RequiresOptIn'
            freeCompilerArgs += '-opt-in=kotlin.Experimental'
        }
    }
}

```

#### `arguments = ["room.incremental": "true"]`

Roomのワーニングを消すための設定。以下のように記載する。

```groovy:build.gradle
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.incremental": "true"]
            }
        }

```
[How to get rid of Incremental annotation processing requested warning?](https://stackoverflow.com/questions/57670510/how-to-get-rid-of-incremental-annotation-processing-requested-warning)

#### `sourceSets`

設定ファイル、ソースの置く位置を通常から変えたい時に利用できる。

[2つのBuild Typeで同じsrcを参照したい](https://qiita.com/Horie1024/items/bf1e7a99cdaa5adbf0cd)
[ソースセットでビルドする](https://developer.android.com/studio/build/build-variants?hl=ja#sourceset-build)

#### `buildFeatures`

さまざまなビルド時の設定をon/offできる。

```groovy:build.gradle
    buildFeatures {
        compose true
    }
```



[BuildFeatures](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/dsl/BuildFeatures)

## gradlew

gradleのラッパーである。

- gradlewとgradlew.batという2つの実行ファイルができる。前者はLinux/macOS用、後者はWindows用
- gradleはHomebrewでインストールしたときのバージョンになるが、gradlewは特定のバージョンのGradleに固定化される。なので、もしローカルにgradleがあったとしても、バージョンが異なれば、gradleをインストールされる。
- 新規参加の開発者にgradleのインストールを頼まなくてもいい。(勝手にインストールされるから)
チームでgradleのバージョンが勝手に統一され、再現性の高いビルド環境になる。
CIなどでgradleを使えば一貫した信頼性のあるビルドになる。
- 通常、ビルド・クリーンなどの実行はAndroid Studioのボタンを押してやると思うが、コマンドから実行するときはgradlewを使える。

    - クリーン: `./gradlew clean`
    - ビルド: `./gradlew build`
        - ビルド(デバッグ情報つき): `./gradlew build --stacktrace`, `./gradlew build --info`, `./gradlew build --debug`, `./gradlew build --scan`


[gradleとgradlewの違い](https://qiita.com/suin/items/266830c0ce37e823916d)より引用

- gradlewの仕組みについてAIに解説してもらった。多分あってるとは思う。

```
Gradle Wrapper（通称 `gradlew`）は、Androidアプリ開発やその他のJava/Kotlinベースのプロジェクトで広く使用されるツールです。この仕組みは、開発環境に依存せず、特定のGradleバージョンを使用してビルドを実行できるように設計されています。以下では、Gradle Wrapperの内部仕組みについて詳しく解説します。

---

### 1. **Gradle Wrapperとは**
Gradle Wrapperは、Gradleのインストールや設定を不要にし、プロジェクト固有のGradleバージョンを自動的にダウンロードして使用するための仕組みです。これにより、チーム内の全員が同じGradleバージョンを使用でき、ビルドの一貫性を保つことができます。

具体的には、以下のファイルで構成されます：
- `gradlew`（Unix系OS用のスクリプト）
- `gradlew.bat`（Windows用のスクリプト）
- `gradle-wrapper.jar`（Gradle Wrapper自体の実装）
- `gradle-wrapper.properties`（Gradleのバージョンや設定を記述）

---

### 2. **Gradle Wrapperの動作フロー**
Gradle Wrapperの動作を段階ごとに説明します。

#### (1) 初回実行時の動作
1. 開発者がプロジェクトルートで`./gradlew <タスク名>`を実行すると、`gradlew`スクリプトが呼び出されます。
2. `gradlew`スクリプトは、`gradle-wrapper.properties`ファイルを読み込みます。このファイルには以下のような設定が含まれています：
   ```properties
   distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
   ```
   - `distributionUrl`には、使用するGradleバージョンのZIPファイルのURLが指定されています。
3. 指定されたGradleバージョンがローカルマシンに存在しない場合、`gradle-wrapper.jar`が`distributionUrl`からGradleバイナリをダウンロードします。
4. ダウンロードされたGradleバイナリは、通常`~/.gradle/wrapper/dists/`ディレクトリにキャッシュされます。
5. ダウンロード後、指定されたGradleバージョンを使用してビルドタスクが実行されます。

#### (2) 2回目以降の動作
- すでに指定されたGradleバージョンがローカルにキャッシュされている場合、再度ダウンロードを行うことなく、キャッシュされたGradleを使用してビルドが実行されます。

---

### 3. **Gradle Wrapperの内部構造**
Gradle Wrapperの各コンポーネントの役割を詳しく見ていきます。

#### (1) `gradlew` / `gradlew.bat`
- `gradlew`はUnix系OS用のシェルスクリプト、`gradlew.bat`はWindows用のバッチファイルです。
- これらのスクリプトは、`gradle-wrapper.jar`を実行するためのエントリーポイントとして機能します。
- 実行時に、システムのJava環境を利用して`gradle-wrapper.jar`を起動します。

#### (2) `gradle-wrapper.jar`
- Gradle Wrapperのコアとなる実装が含まれるJARファイルです。
- 主な機能：
  - `gradle-wrapper.properties`を解析して、必要なGradleバージョンを特定。
  - 必要に応じてGradleバイナリをダウンロード。
  - ダウンロードしたGradleバイナリを実行。

#### (3) `gradle-wrapper.properties`
- Gradle Wrapperの設定ファイルです。
- 主なプロパティ：
  - `distributionUrl`: 使用するGradleバージョンのZIPファイルのURL。
  - `distributionPath`: ダウンロードしたGradleバイナリの保存先パス（デフォルトは`wrapper/dists`）。
  - `zipStorePath`: ZIPファイルのキャッシュ先パス。
  - `distributionBase`: バイナリのベースディレクトリ。

---

### 4. **Gradle Wrapperの利点**
Gradle Wrapperを使用することで、以下のメリットがあります：
1. **環境依存の排除**:
   - 各開発者が個別にGradleをインストールする必要がありません。
   - プロジェクトごとに異なるGradleバージョンを使用できるため、互換性問題を回避できます。
2. **ビルドの一貫性**:
   - 全ての開発者やCI/CD環境で同じGradleバージョンを使用できるため、ビルド結果の一貫性が保たれます。
3. **簡単なセットアップ**:
   - 新しい開発者がプロジェクトに参加する際、Gradleのインストールや設定を意識する必要がありません。

---

### 5. **Gradle Wrapperのカスタマイズ方法**
Gradle Wrapperの設定を変更するには、以下の手順を行います：
1. `gradle wrapper`タスクを実行してWrapperを更新します。
   ```bash
   ./gradlew wrapper --gradle-version 8.0
   ```
   上記コマンドを実行すると、`gradle-wrapper.properties`の`distributionUrl`が指定したバージョンに更新されます。

2. 必要に応じて、`gradle-wrapper.properties`を直接編集することも可能です。

---

### 6. **まとめ**
Gradle Wrapperは、Gradleのインストールや設定を自動化し、プロジェクト固有のGradleバージョンを使用してビルドを実行するための仕組みです。内部的には、`gradlew`スクリプトと`gradle-wrapper.jar`が連携して動作し、必要に応じてGradleバイナリをダウンロード・実行します。これにより、開発環境の違いによる問題を回避し、ビルドの一貫性を確保することができます。

もしさらに詳細な技術的な質問があれば、お気軽にお知らせください！
```

## local.properties

Android SDK がPCのどこにあるかを記載する。これは各PCごとに異なるべき情報であるから、このファイルをGitの変更管理に入れてはいけない。

```:local.properties
sdk.dir=/Users/XXXXXXX/Library/Android/sdk
```

## AndroidManifest.xml

アプリに関する設定を記載するもの。パッケージ名やアプリケーションID、アプリで作成したコンポーネント、ユーザーに求めるパーミッション、アプリが必要とするハードウェア機能やソフトウェア機能のタイプなどなど。build.gradleと重複する部分もあり、その部分はbuild.gradleに書いた設定で上書きされる。公式マニュアルが充実しているのでそこを見た方が早いか。

- 以下、引用


> 要素
必須の要素は manifest と application のみです。 これらの要素は一度だけ指定します。 その他のほとんどの要素は、一度も指定しなくても、複数回指定しても構いません。 ただし、マニフェスト ファイルを有用なものにするには、指定しなければならないものもあります。
すべての値は属性によって設定され、要素内に文字データが設定されることはありません。

> 通常、同じレベルにある要素に順番はありません。 たとえば、activity、provider、service の各要素を任意の順番で指定できます。 このルールには 2 つの重要な例外があります。

> activity-alias 要素は、それがエイリアスとなる activity の後に指定しなければなりません。
application 要素は、manifest 要素内の最後の要素でなければなりません。

- 以上、引用 [アプリ マニフェストの概要](https://developer.android.com/guide/topics/manifest/manifest-intro?hl=ja#filec)
- こちらも参考: [アプリの基礎](https://developer.android.com/guide/components/fundamentals?hl=ja#Components)



## gitignore

gitignoreでmacos, android, androidstudioなどと指定して生成されたものを使えばいいのではないかと思われる。

[gitignore.io - macos, android, androidstudio](https://www.toptal.com/developers/gitignore/api/macos,android,androidstudio)

あるいは、GitHubにAndroid.gitignoreの推奨が置かれている。

[gitignore/Android.gitignore](https://github.com/github/gitignore/blob/main/Android.gitignore)

## 多言語対応

### strings.xml

デフォルトで存在するstrings.xmlにて、Android studioで右クリックし、"Open Translation Editor"をクリックすると、多言語の追加画面が開く。ここで、あるキーに対して、各言語でどのような文字列とするか指定できる。

![截屏2023-07-26 13.56.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/3fce9115-787b-f667-8a37-724fb26184f8.png)
![截屏2023-07-26 13.58.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392332/f49d42df-9ea0-d82b-5395-d46b802ab291.png)

無論、xmlファイルであるから直接ファイルを編集しても構わない。


文字列を使いたい時は、たとえばcomposeでは以下のように使う。

```kotlin:test.kt
import com.example.exampleapp.R
import androidx.compose.ui.res.stringResource

Text(text = stringResource(id = R.string.home_title)
```
以下のように使う。

```kotlin:example_activity.kt
// Get a string resource
val hello = resources.getString(R.string.hello_world)
```

参考

[Android Developers - 各種の言語と文化をサポートする](https://developer.android.com/training/basics/supporting-devices/languages?hl=ja)
[Android Developers - アプリをローカライズする](https://developer.android.com/guide/topics/resources/localization?hl=ja)
[Localizing String Resources / Translations Editor - Android Studio Tutorial](https://www.youtube.com/watch?v=72qURZPIUIA)
[Unresolved reference: string](https://stackoverflow.com/questions/72161678/unresolved-reference-string)
[getString Outside of a Context or Activity](https://stackoverflow.com/questions/4253328/getstring-outside-of-a-context-or-activity)


## apkファイルを解析したい

Android StudioのBuild > Analyze apk をクリックし、apkファイルを指定すると、apkファイルの中身を解析できる。

参考: [Analyze your build with the APK Analyzer](https://developer.android.com/studio/debug/apk-analyzer)

## Kotlin

### 文法


[３０分で覚えるKotlin文法](https://qiita.com/k5n/items/cc0377b75d8537ef8a85)


#### `return` の後ろの `@`マーク

`forEachIndexed`などの関数において、これはforループではないためbreakやcontinueが使えない。そのため、ラベル付きのreturn文として`return@forEachIndexed`のような書き方をする。これで、continueと同じような機能となる。(普通に`return`と書けばbreakのような機能となる)

[Kotlinの@[アットマーク]について](https://qiita.com/AAkira/items/99028e20fcfe1a79af95)


#### `LinkedHashMap`, `HashMap`

キーバリュー形式で値を保持する。キーの重複は許さない。
Linkedの方は順番も保持する。普通の`HashMap`の方は順番は保持しない。

[JavaのLinkedHashMapクラスの使い方を現役エンジニアが解説【初心者向け】](https://magazine.techacademy.jp/magazine/22165)

#### `sealed` クラス

enum に似ているが、状態を持つことができる。また、典型的には、その内部クラスとして自分自身を継承させたクラスを作ることで、用いる。また、よくwhen節と共に用いる。


```kotlin:Result.kt
/**
 * A generic class that holds a value or error.
 * @param <T>
 */
sealed class Result<out R> {

    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()

    override fun toString(): String {
        return when (this) {
            is Success<*> -> "Success[data=$data]"
            is Error -> "Error[exception=$exception]"
        }
    }
}

```



#### `!!`:　`double-bang operator`: not-null assertion operator 

#### スコープ関数
    - [Scope functions](https://kotlinlang.org/docs/scope-functions.html#takeif-and-takeunless)

#### `by`: 移譲を簡単にできるオペレータ。
    
- 以下、引用

```
委譲とはあるオブジェクトの操作を一部他のオブジェクトに代替させる手法である
委譲ではあるオブジェクトの操作を他のオブジェクトに代替させるため冗長な記述が増えてしまいがち
だが Kotlinの by を利用することで冗長な記述をせず、簡単に操作を委譲させることができる。
```


- 以上、引用([［Kotlin］`by` で 委譲する仕組みを理解する](https://qiita.com/kaleidot725/items/82bde22ef077101e4268))

#### extension 


- 以下、引用

```kotlin:main.kt
fun main(args : Array<String>) {
    "extensions".hoge()
}

fun String.hoge() {
    println("<$this>")
}

```

- 以上、引用 [Kotlin の Extensions について色々試す](https://qiita.com/opengl-8080/items/a7cdd746131337e7c9a6)より

#### `Unit`とは

Javaでいう`Void`のようなもので、何も返さないメソッドの戻り値として用いることがある。

#### 可視性修飾詞
- `public`: どこからでも閲覧可能。何もつけなければこれとなる。
- `internal`: 同一モジュールからのみ閲覧可能。
- `private`: 同一ファイルないからのみ閲覧可能
- `protected`: クラス内での宣言のみ付加可能。`private`に加え、サブクラスからも閲覧できる。

[可視性修飾詞](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/visibility-modifiers.html)

#### Nullableな値がnullかどうかチェックするには

セーフコールオペレータ`?.`とエルビスオペレータ`?:`を組み合わせると良さそう。

```kotlin:test.kt
a?.let {
   println("not null")
   println("a: $it")
} ?: run {
    println("null")
}
```

[Best way to null check in Kotlin?](https://stackoverflow.com/questions/37231560/best-way-to-null-check-in-kotlin)

複数の値が全部nullでないことをチェックする時はあまり良い書き方がなさそう。`if (p1 != null && p2 != null)`などと汚く書くしかないだろう。

[Multiple variable let in Kotlin](https://stackoverflow.com/questions/35513636/multiple-variable-let-in-kotlin)

## 自分のアプリから、他のアプリを開きたい。

Deep links（インテントを使った、一般的な方法）と、AppLinks(こちらもインテントは使っているが、URLのスキーマはHTTP(S)かつ開かれるアプリ側で特殊な設定が必要)が利用できるようである。

[Handling Android App Links](https://developer.android.com/training/app-links/index#android-app-links)

## targetSDK アップデート

近年は毎年８月に、Google Playにアップロードするアプリのtarget SDKを上げることが要求される。2023/8/1からはAPI 33 以上にすることが要求される。それに伴い様々な対応が必要になることもある。

参考: [targetSdkVersion 33 対応でやったこと](https://qiita.com/koichi-ozaki/items/883427922399788632a7)

## ライブラリ

### [diffplug/spotless](https://github.com/diffplug/spotless)

コードのフォーマッター（コードをきれいにしてくれるやつ）

[KtLint + Spotless + GitHub ActionsでPRにsuggested changeさせる](https://qiita.com/takahirom/items/2a3d2912e74107748765)

### [Timber](https://github.com/JakeWharton/timber)

ロガー。

#### インストール

```groovy:build.gradle
repositories {
  mavenCentral()
}

dependencies {
  implementation 'com.jakewharton.timber:timber:5.0.1'
}

```

#### 使用方法

- 以下、引用
- アプリケーションクラスで、`Tree`クラスインスタンスを初期化する。

```kotlin:MyApplication.kt
@HiltAndroidApp
class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
    }
}

```

- `Timber`のスタティックメソッドをログを出したいところでよぶ。
- 以上、引用 [JakeWharton/timber](https://github.com/JakeWharton/timber)

### 画像ダウンロード・キャッシュ関連のライブラリ

Glide / Picasso / Coil などが存在するが、Jetpack Composeに対応しているのはCoilである模様。

[3つの画像読み込みライブラリ Glide / Picasso / Coil - JetpackCompose 対応の状況](https://android.benigumo.com/20220801/glide-picasso-coil/)

#### Coil

gradleに以下の文言を追加してインストール。
```Groovy:.
implementation("io.coil-kt:coil-compose:2.4.0")
```

jetpack compose を使っている場合の、画像の表示方法は以下となる。

```kotlin:test.kt
AsyncImage(
    model = "https://example.com/image.jpg",
    contentDescription = null,
)
```


### Lottie-Android

Json形式でアニメーションが定義されており、簡単にアニメーションを実装できる。なお、iOS, React Native, Webでも使える。

[lottie-android](https://github.com/airbnb/lottie-android)
[Lottie-Androidで素晴らしいアニメーション試す](https://qiita.com/ikemura23/items/8c5f87f98cb7fc3ceb27)


ドキュメントは以下:

[Lottie doc](https://airbnb.io/lottie/#/README)

## テスト

### 単体テスト・UIテスト
テストはデフォルトでも行える。WebViewのテストを行うときはデフォルトではやりきれないため、AppiumかEspressoなどライブラリを使うと良い。

単にWebViewのみテストする場合はAppium, NativeとWebViewのやりとりも含めてテストする場合はEspressoが推奨されている。
参考[Espresso-Web](https://developer.android.com/training/testing/espresso/web?hl=ja#when-to-use)

#### Appium
WebViewのテストを行うときはデフォルトではやりきれないため、Appiumなどライブラリを使うと良い。
導入がやや複雑であるため注意。

[AppiumでAndroid/iOSアプリのテストコードを書いてみた](https://qiita.com/lethe2211/items/917ec62d27d5384f5685#appium-inspectorを用いてui要素のlocatorを探す)

#### Truth
Google公式のライブラリで、Unitテストを書きやすくしてくれる。
[Google/Truth](https://github.com/google/truth)

#### Robolectric

Activity, JetpackComposeなどUI部品の振る舞いのテストを高速で行ってくれる。端末、エミュレータを使うよりも早くできる。

[公式サイト](https://robolectric.org/#kotlin)
[Robolectricを使ったAndroid端末を使わないユニットテストを行う第一歩](https://qiita.com/LyricalMaestro0/items/4149ac20038cffddb47d)

公式解説サイト: https://truth.dev

#### JetpackCompose @Preview

UI部品のみためのテストについては、Composableについては@Previewで行うことになるだろう。端末、APIレベル、ダークモード、画面サイズなど様々な指標で見た目の確認を行える。

[コンポーザブルのプレビューで UI をプレビューする](https://developer.android.com/develop/ui/compose/tooling/previews)
[Preview]()

#### スクリーンショット比較
目視比較でも良いが、画面のスクリーンショットを比較してくれる機能であるScreenshot Testingが登場した。2024年から、Jetpack Composeのみだが利用できる。

[Compose プレビューのスクリーンショットのテスト](https://developer.android.com/studio/preview/compose-screenshot-testing?hl=ja)

### 結合テスト・受入テスト

Google Play Storeからアプリを配布する方法として、アプリを公開する以外にも方法があり、これらの方法で受け入れテストなどをしていくことになる。内部テスト・クローズドテスト・オープンテストである。

[Play Console ヘルプ - オープンテスト版、クローズド テスト版、内部テスト版をセットアップする](https://support.google.com/googleplay/android-developer/answer/9845334?hl=ja)
[Google Playでの配信方法の整理](https://product.st.inc/entry/2023/02/20/140359)

## セキュリティ

[『Androidアプリのセキュア設計・セキュアコーディングガイド』](https://www.jssec.org/report/android_securecoding_20250129.html)

## パフォーマンス

### R8

R8という最適化ツールが利用できる。リリースビルドにおいて有効化するのが常套手段となる。

```kotlin:build.gradle.kts(:app)
android {
    buildTypes {
        release {

            // Enables code-related app optimization.
            isMinifyEnabled = true

            // Enables resource shrinking.
            isShrinkResources = true

            proguardFiles(
                // Default file with automatically generated optimization rules.
                getDefaultProguardFile("proguard-android-optimize.txt"),

                ...
            )
            ...
        }
    }
    ...
}
```

参考: [アプリの最適化を有効にする](https://developer.android.com/build/enable-app-optimization?hl=ja)

### レイアウトインスペクタ
[安定性の問題を診断する - LayoutInspector](https://developer.android.com/develop/ui/compose/performance/stability/diagnose?hl=ja#layout-inspector)

### Profiler

[アプリ パフォーマンスのプロファイリング](https://developer.android.com/studio/profile?hl=ja)

### JetpackCompose のフェーズ

[Jetpack Compose のフェーズ](https://developer.android.com/develop/ui/compose/phases?hl=ja#phase1-comp)

JetpackCompose にはフェーズが三つ（Compose, Layout, Drawing）があり、最初のComposeフェーズをスキップできるとパフォーマンスが向上する。

Modifierについて、値を渡すModifierではなくラムダとして値を設定するModifierを選ぶと、ComposeフェーズはスキップされLayout, Drawingのみ行われる。そのため、パフォーマンスが問題となっている部分については値を渡すModifierを使っていれば、それはやめてラムダとして値を設定するModifierで同じ動作を実現できないか調べるといいだろう。

### JetpackCompose derivedStateOf

頻繁に更新されるStateをそのまま閲覧すると頻繁にコンポーズが走ってしまい、パフォーマンスに悪い。そのStateについて何らかの条件が満たされたときだけ更新される新たなStateを派生的に作り出せるのがこのderivedStateOfであり、パフォーマンス改善に役立つ。

例えばリストの`listState.firstVisibleItemIndex`はリストをスクロールするたびに頻繁に更新されるため、直接参照するのではなく、derivedStateOfを経由して参照することで、更新頻度を抑えることができる。

[Composeにおける副作用 - derivedStateOf](https://developer.android.com/develop/ui/compose/side-effects?hl=ja#derivedstateof)

### JetpackCompose @Immutable

全てのプロパティが定数（`val`）で構成していても、URL型など基本型以外のプロパティを含むクラスは不安定なクラスとして認定されてしまい、結果として余計な再コンポーズが発生することがある。

`@Immutable`アノテーションを付与すると強制的に不変なクラスとして認識させることができ、問題を解決できることがある。

[安定性に関する問題を解決する - Stable または Immutable でアノテーションを付ける](https://developer.android.com/develop/ui/compose/performance/stability/fix?hl=ja#annotate-stable)

### JetpackCompose LazyColumnなどのKey

LazyColumnなどでアイテムの順番が変わったりすると、違うアイテムになったと認識され全部再コンポーズされることがある。LazyColumnなどに用意されているKeyパラメ〜たを指定すると、順番が変わっても同一アイテムを認識でき、不要なコンポーズはスキップされる。

[リストとグリッド - アイテムのキー](https://developer.android.com/develop/ui/compose/lists?hl=ja#item-keys)


## エラー

### Setting the namespace via a source AndroidManifest.xml's package attribute is deprecated. Please instead set the namespace (or testNamespace) in the module's build.gradle file

AndroidManifest.xmlのpackage要素はdeprecatedとなっているので、それを削除し、代わりにbuild.gradle(:app)にnamespace要素を追加すると治った。

[Android Manifest merge error when removing package name for namespace](https://stackoverflow.com/questions/71775818/android-manifest-merge-error-when-removing-package-name-for-namespace)

### Activity at AndroidManifest.xml:20:9-30:20 duplicated with element declared at AndroidManifest.xml:11:9-19:20

誤って同じActivityを2回AndroidManifest.xmlに宣言してしまっていたので、一つにすると治った。

### Expected @HiltAndroidApp to have a value. Did you forget to apply the Gradle Plugin?

`build.gradle`において、`annotationProcessOptions`という設定を上書きしてしまっていたために発生していた。`annotationProcessOptions = `という書き方ではなく、`annotationProcessOptions +=` という書き方にしなくてはならない。

[Expected @HiltAndroidApp to have a value. Did you forget to apply the Gradle Plugin?](https://stackoverflow.com/questions/62887817/expected-hiltandroidapp-to-have-a-value-did-you-forget-to-apply-the-gradle-plu)


###  [Dagger/MissingBinding] XXX cannot be provided without an @Provides-annotated method.

あるクラスXXXがDaggerでDIをするのに必要になる旨を自分で記載しているにもかかわらず、そのクラスをどのように初期化すればいいのかがDaggerに伝わっていない。指示通り、@Providesのついた初期化のための関数を作り、どこかのmoduleで定義すれば解決する。

[Stack Over Flow - Dagger 2: Cannot be provided without an @Provides-annotated method](https://stackoverflow.com/questions/43116825/dagger-2-cannot-be-provided-without-an-provides-annotated-method)

### java.lang.ClassNotFoundException Didn't find class "XXXXXApplication" on path

`AndroidManifest.xml`において`<application android:name="XXXXXXXApplication" `の箇所で指定すべきファイルの箇所が間違っていた。該当ファイルを確認し、パッケージのパスを確認した上で、修正したところ、治った。

[Stack Over Flow - java.lang.ClassNotFoundException: Didn't find class on path: dexpathlist](https://stackoverflow.com/questions/22399572/java-lang-classnotfoundexception-didnt-find-class-on-path-dexpathlist)


### 'Failed to install-write all apks'

実機でアプリをインストールしようとする場合はその実機、シミュレータの場合はコンピュータ、のメモリが足りなかったりする場合に起こる。メモリを開けたり、再起動したりすると治る。筆者の場合は再起動すると治った。

[I am getting error- 'Failed to install-write all apks'](https://stackoverflow.com/questions/70120277/i-am-getting-error-failed-to-install-write-all-apks)

### `Flutter General error during conversion: Unsupported class file major version xx`

Gradleのバージョンを新しくすると直りました

[Flutter General error during conversion: Unsupported class file major version xxと出た場合の対処](https://zenn.dev/sakuraapps/scraps/6a114aa02bc851)

### `flutter Namespace not specified. Please specify a namespace in the module's build.gradle file like so`

`namespace "com.example.myapp"`という記述がbuild.gradleに必要なところ、書いていなかった。"com.example.myapp"という部分は、通常はアプリケーション ID と同じにする。

[アプリ モジュールを設定する](https://developer.android.com/studio/build/configure-app-module?hl=ja#set-namespace)


### java.lang.RuntimeException: Unable to start activity ComponentInfo Activity java.lang.IllegalStateException Hilt Activity must be attached to an @HiltAndroidApp Application Did you forget to specify your Application's class name in your manifest's <application />'s android:name attribute?

Hiltに関するエラーで、@HiltAndroidAppマークをつけたクラスのクラス名を、AndroidManifest.xmlに記載する必要がある。

```kotlin:MultiTranslationApplication.kt
@HiltAndroidApp
class MultiTranslationApplication : Application() {

    override fun onCreate() {
        super.onCreate()
    }
}
```

```xml:AndroidManifest.xml
    <application
        android:name="MultiTranslationApplication"
        ....
```

### Unable to start activity ComponentInfo java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity

MainActivityのテーマとして、`Theme.AppCompat`またはそれを継承したテーマを使わないと、古い端末などではうまく働かないことがあるので、これを使うようにする。

`AndroidManifest.xml`において、以下のテーマを最後の行のように記載すると治った。

```xml:AndroidManifest.xml
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.AppCompat">
```

[Geeks for Geeks - Android – You need to use a Theme.AppCompat theme (or descendant) with this activity](https://www.geeksforgeeks.org/android-you-need-to-use-a-theme-appcompat-theme-or-descendant-with-this-activity/)

### アプリの一番上にアプリ名が書いてあるバーが表示されるが、消したい。

`AndroidManifest.xml`において、使うテーマをActionBarなしのものとする。

```xml:AndroidManifest.xml
   <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.AppCompat.NoActionBar">
```

[Android remove action bar](https://stackoverflow.com/questions/35617352/android-remove-action-bar)

### エミュレータが作動しない

理由はよくわからなかったが、Android studioよりdevice managerを起動し、一度該当端末のエミュレータを停止させてからもう一度動かすと出現した。

### Could not get unknown property 'source' for generate-proto-generateDebugProto of type org.gradle.api.internal.file.DefaultSourceDirectorySet

Proto Datastoreを使う際に必要な`protobuf`ライブラリのバージョンが古かったようなので、新しいもの(0.9.1)を指定したら治った。

[Proto datastore jetpack compose - gradle dependencies exception](https://stackoverflow.com/questions/76175068/proto-datastore-jetpack-compose-gradle-dependencies-exception)

### Execution failed for task app generateDebugProto Could not resolve all files for configuration app:protobufToolsLocator_protoc Could not find protoc-3.14.0-osx-aarch_64.exe

`protobuf`ライブラリの古いバージョンはM1 Macをサポートしていないのでこのようなエラーが発生するらしい。`protobuf`ライブラリを3.19.4に上げたら治った。

[Protoc can not be executed on M1 based Macs #43](https://github.com/android/codelab-android-datastore/issues/43)

### @dagger.hilt.android.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method.

Hiltで依存性注入を行っていた。ProtoDatastoreをラップしたクラスを注入する必要があった。

```kotlin:LanguageSettingsDataStore.kt
class LanguageSettingsDataStoreWraper @Inject constructor(@ApplicationContext context: Context) {
    val dataStore = context.languageSettingsDataStore
}
```

このクラスは`Context`を必要としている。Hiltで`Context`を提供するには`@ActivityContext`か`@ApplicationContext`がある。前者を用いたらこのようなエラーが発生した。しかし後者を用いたら解消した:

```kotlin:DataModules.kt
@Module
@InstallIn(SingletonComponent::class)
object ObjectModule {
    @Provides
    @Singleton
    fun provideLanguageSettingsDataStoreWrapper(@ApplicationContext context: Context): LanguageSettingsDataStoreWraper {
        return LanguageSettingsDataStoreWraper(context)
    }
}
```

理由がよくわからない部分もあるが、`SingletonComponent`を用いる場合は、(アプリ起動時からアプリ終了時までずっと存続すべきクラスということになるので？)`@ApplicationContext`を用いろとの記述が[公式ドキュメント](https://developer.android.com/training/dependency-injection/hilt-android#not-supported)にあった。

その他参考
:
[How to inject application context in a repository with Hilt?](https://stackoverflow.com/questions/63072927/how-to-inject-application-context-in-a-repository-with-hilt)
[Dagger Hilt の Context まわりでハマったこと](https://zenn.dev/kmd_htsh0226/articles/5ea197bc242e6e67d47a)

### Update this project to use a newer compileSdk of at least
下記記事の通り、`build.gradle.kts (Module :app)`の`compileSdk`と`targetSdk`の値を上げたら治った。

[Update this project to use a newer compileSdk of at least , for example 解決方法](https://qiita.com/Nw3965/items/48d466c213423c081bae)

### LiveData の MediatorLiveDataを使っているのだが、値が流れてこない。

MediatorLiveDataを購読しているアクティブなオブザーバーが一つ以上ないと、値を流さないようになっている。最低限一回は購読されるようにすると、値が流れた。
[Stack Over Flow - MediatorLiveData onChanged not getting called](https://stackoverflow.com/questions/52404536/mediatorlivedata-onchanged-not-getting-called)

### FileIntegrityManager(android.security)が初期化できない

Context(Activityなど)のgetSystemService(FileIntegrityManager::class.java)関数で初期化する。わからなかったので自分でStackOverFlowに質問した。

参考: [How do I instantiate FileIntegrityManager in Android?](https://stackoverflow.com/questions/78243776/how-do-i-instantiate-fileintegritymanager-in-android)


### @HiltViewModelアノテーションで初期化しているViewModelについてなんらかのカスタム設定を手動でしたい。

`init {}`メソッドを設ければそのメソッドは初期化時に呼ばれるので、なんらかの設定を自由にその中で行うことができる。

なんらかの値をViewModelに渡し、その値を使って初期設定をしたいという場合は、@Assistedというアノテーションを利用すると、その値を利用して初期設定が可能となる。

[Instantiate viewModel with run-time arguments using Hilt](https://stackoverflow.com/questions/70055034/instantiate-viewmodel-with-run-time-arguments-using-hilt)

### LiveDataのMediatorLiveDataを使っていたところ、`Attempt to invoke interface method 'void androidx.lifecycle.Observer.onChanged(java.lang.Object)' on a null object reference`が発生した。

以下のようなコードにおいて、このエラーが発生した。

```kotlin:NullPointerError.kt
    private val myMediator = MediatorLiveData<Int>().apply {
        addSource(someSource) {
            // Set something to value
        }
        observeForever(myObserver)
    }
    private val myObserver = Observer<Int> {
        Log.d("My App", "myObserver: new value: $it")
    }
```

`observeForever(myObserver)`として`myObserver`を使っているが、この際にはまだ`myObserver`が初期化されていないのでnullとなってしまう。`observeForever(myObserver)`よりも前に`myObserver`を宣言すると解消した。

```kotlin:AfterFix.kt
    private val myObserver = Observer<Int> {
        Log.d("My App", "myObserver: new value: $it")
    }
    private val myMediator = MediatorLiveData<Int>().apply {
        addSource(someSource) {
            // Set something to value
        }
        observeForever(myObserver)
    }
```

参考: [MediatorLiveDataでNullPointerExceptionが出たときの対処法](https://qiita.com/gorigorigorilla/items/3710b09144a30596a4df)

### Android Emulator System Imageがダウンロードできない。

原因はいろいろありうると思うが、今回はタイムアウトとなってしまっていた。その場合、Android StudioのSettings > Languages & Frameworks > Android SDK でShow Package Detailsで詳細を表示し、必要なものを一つずつチェックし、Applyボタンを押していくと、一つずつダウンロードできるので、成功した。

参考: https://stackoverflow.com/a/65792765

### .gradlew/ の実行時に、 The operation couldn’t be completed. Unable to locate a Java Runtime.　と表示される。

JAVAが見つからないため、このようになっている。環境変数のpath(zshellなら`.zprofile`など)として`JAVA_HOME`を追加すると解消した。

```sh:.zprofile
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home
```

### rememberメソッドを使ったところ`Type 'MutableState<Int>' has no method 'setValue(Nothing?, KProperty<*>, Int)' and thus it cannot serve as a delegate for var (read-write property)`というエラーが出た。

`import androidx.compose.runtime.setValue`とインポートをしたら解消した。