@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