@Composable の LifecycleOwner は誰なのか - collectAsStateWithLifecycle
Compose までの Flow の collect
coroutine など非同期処理を行う場合ライフサイクルの考慮が必要でしたね!
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(STARTED) {
myViewModel.myUiState.collect {
// ...
}
}
}
これは、Fragment のビューが STARTED になったときに収集を開始し、RESUMED まで継続し、STOPPED に戻ったときに停止します。

👉 【MVVM】 Kotlin Flow で使える5つの利用パターン
生き死にだけでではないのです。
collect する期間も考えなくてはなりません。
Compose では
@Composable 内で、
val items by viewModel.items.collectAsState(initial = emptyList())
というような形で、かんたんに Flow や StateFlow を 収集できます。
しかし、
バックスタック中に、無駄に APIにリクエストしたり、DBにクエリーを投げたりしてません?
逆に、更新されずに古いままの更新されてない画面見せられたりして萎えたりもします。
collectAsStateWithLifecycle() の登場
👉 collectAsStateWithLifecycleが追加されたぞ - Qiita
所属は以下のようです。

implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.0-alpha01"
実装を見てみます。
ホットな StateFlow と コールドな Flow に向けて2つずつ公開されています。
fun <T> StateFlow<T>.collectAsStateWithLifecycle(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
context: CoroutineContext = EmptyCoroutineContext
): State<T>
fun <T> StateFlow<T>.collectAsStateWithLifecycle(
lifecycle: Lifecycle,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
context: CoroutineContext = EmptyCoroutineContext
): State<T>
fun <T> Flow<T>.collectAsStateWithLifecycle(
initialValue: T,
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
context: CoroutineContext = EmptyCoroutineContext
): State<T>
fun <T> Flow<T>.collectAsStateWithLifecycle(
initialValue: T,
lifecycle: Lifecycle,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
context: CoroutineContext = EmptyCoroutineContext
): State<T>
ライフサイクルや期間を与えて collect 動作を設定できます。
ありがとうございます。
LifecycleOwner は誰なのか
前述引用の実装コードより。
...
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
...
LocalLifecycleOwner
ライフサイクルのオーナーといえば、Compose 以前は、
Activity、Fragment、View
ぐらいで考えていましたが。
きっとオーナーは、Activity ではなく、
最上位のルートの @Composable
ではなかろうか。
いや、ワンチャン Activity かもしれん。
見てみましょう。
println("オーナー → ${LocalLifecycleOwner.current}")
結果
D: オーナー → androidx.navigation.NavBackStackEntry@4dc222c4
「NavBackStackEntry」さんらしいですわ。
【Jetpack Compose】Icon() や Image() で ImageVector をより便利に使う
コード記述のみでベクターのマテリアルアイコン使えます。
drawable の作成が不要なので便利、変更もしやすいです。
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = null
)
Image(
imageVector = Icons.Filled.Favorite,
contentDescription = null
)
悪い点としては、
絵柄が49個しかない
絵柄を見ながら選択できない
というところでしょうか。
対応策を考えてみましょう。
絵柄が49個しかない
compose 公式のアイコン群(2500個以上)を追加できます。
implementation "androidx.compose.material:material-icons-extended:x.y.z"
エディタのサジェスチョンも大量に増えます。

ただ、少し読み込みが遅い。
そこらへんは、公式に注意点があります。
警告: material-icons-extended は大規模なライブラリであり、APK のサイズに影響する可能性があります。そのため、製品版ビルドでは R8/Proguard を使用し、使用されていないリソースを取り除くことを検討してください。また、サイズが大きいために、開発中は、プロジェクトのビルド時間と Android Studio のプレビューの読み込み時間が増加する可能性があります。
👉 Compose のリソース | Jetpack Compose | Android Developers
サイズにも注意する必要があるようです。
絵柄を見ながら選択できない
これがすごく困ります。
別で、WEB画面を開くか、Android Studio の Vector Asset Tool を開くかして、絵柄を見て選択して、その名前から、サジェスチョンさせる、くらいしか方法がない。なんかいい方法あったら教えなさいよ。

👉 Material Symbols and Icons - Google Fonts

将来的には、ライブプレビュー(今現在はリテラルのみ)ですばやく見れるようになるのかもしれません。
Android Studio Electric Eel 以降では、ライブ編集を使用して Compose の開発を高速化できます。ライブ編集は、リテラルのライブ編集をより強力にしたものです。この機能では、プレビューを自動的に更新し、コードの変更をエミュレータまたはデバイスにデプロイすることで、コンポーザブルの更新の影響をリアルタイムで確認できます。
👉 Compose のツール | Jetpack Compose | Android Developers
まとめ
将来性を見越して、ImageVector を使って
@Composable
fun LikeButton() {
Button(onClick = {}) {
Icon(
imageVector = Icons.Filled.ThumbUp,
contentDescription = null
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text("Like")
}
}
と書きたいです!

ちなみに、これまでのように ベクター drawable を作成して、id で使う記述もできます。
Icon(
painter = painterResource(id = R.drawable.ic_baseline_favorite_24),
contentDescription = null
)
しかし、変更時に drawable 消し忘れでゴミが溜まりそう。
あと、
Icons.Default は Icons.Filled のエイリアス
だそうです。
👉 Android Jetpack Compose Icons doesn't contain some of the material icons - Stack Overflow
Jetpack Compose Codelabs の日本語ページの説明とGitHub内サンプルコードが違う件

各タイトルのリンクから飛べるドキュメントを見る限り、文章が全く違い、英語ページと日本語ページの最終更新日が数ヶ月違います。
仕様の変化の早い Jetpack Compose ではつらいです。
以下、2022-06-11 現在。

日本語の説明ページの翻訳作業が遅れてるのでしょう。
問題なのは、日本語記事の説明に対して GitHub リポジトリのソースコードが違うことです。
細かく探すとあるのかもしれませんが。



👉 tree/end - Jetpack Compose Codelabs
あと、説明ページの表示が10秒くらいかかるの何でなんだろ?
AGP Upgrade Assistant で 7.2 移行時にCause: manifestData.`package` must not be null
初回は、自動認識でダイアログから進むことになると思うが、
手動でやるなら以下から。
[Tools]
↓
[AGP Upgrade Assistant]
このステップでコケる。
Move package from Android manifest to build files
Declaration of a project's namespace using the package attribute of the Android manifest is deprecated in favour of a namespace declaration in build files.

なんすかねこれ。
Gradle sync failed: Cause: manifestData.`package` must not be null
Issue Tracker にありました。
AGP namespace property and app id suffix and Safe Args plugin don't work together
Using the new namespace property in build.gradle instead of the package attribute in AndroidManifest.xml while also using a custom applicationIdSuffix breaks androidx.navigation.safeargs plugin.
👉 Gradle sync failed: Cause: manifestData.`package` must not be null - Issue Tracker
👉 AGP namespace property and app id suffix and Safe Args plugin don't work together [232107688] - Visible to Public - Issue Tracker
どうやら、namespace の新記述は、
androidx.navigation.safeargs と同時に使えないようです。
使っているか、コード内を探してみました。
[Edit]
↓
[Find]
↓
[Find in Files ...]

...
どうやら、ツールの書き換え内容は以下の様子。
👉 AndroidManifest の package 属性による名前空間宣言が廃止される - BattleProgrammerShibata
2行だけなので直接書き換えて namespace 記述は以前の形に戻す。と。
暫定的な対応なので、以下のようにFix版リリース時に注意が必要です。