Android OS version Market Share

👉 Android OS バージョン確認方法 (platform versions) hatena-bookmark

👉 🚀 iOS Version Market Share hatena-bookmark


@Composable の LifecycleOwner は誰なのか - collectAsStateWithLifecycle

 

Compose までの Flow の collect

coroutine など非同期処理を行う場合ライフサイクルの考慮が必要でしたね!


viewLifecycleOwner.lifecycleScope.launch {
  viewLifecycleOwner.lifecycle.repeatOnLifecycle(STARTED) {
    myViewModel.myUiState.collect {
      // ... 
    }
  }
}

これは、Fragment のビューが STARTED になったときに収集を開始し、RESUMED まで継続し、STOPPED に戻ったときに停止します。

@Composable の LifecycleOwner は誰なのか - collectAsStateWithLifecycle

👉 【MVVM】 Kotlin Flow で使える5つの利用パターン hatena-bookmark

生き死にだけでではないのです。

collect する期間も考えなくてはなりません。

 

Compose では

@Composable 内で、


val items by viewModel.items.collectAsState(initial = emptyList())

というような形で、かんたんに Flow や StateFlow を 収集できます。

しかし、

バックスタック中に、無駄に APIにリクエストしたり、DBにクエリーを投げたりしてません?

逆に、更新されずに古いままの更新されてない画面見せられたりして萎えたりもします。

 

collectAsStateWithLifecycle() の登場

👉 collectAsStateWithLifecycleが追加されたぞ - Qiita hatena-bookmark

所属は以下のようです。

androidx.lifecycle.lifecycle-runtime-compose


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"

エディタのサジェスチョンも大量に増えます。

androidx.compose.material:material-icons-extended

ただ、少し読み込みが遅い。

そこらへんは、公式に注意点があります。

警告: material-icons-extended は大規模なライブラリであり、APK のサイズに影響する可能性があります。そのため、製品版ビルドでは R8/Proguard を使用し、使用されていないリソースを取り除くことを検討してください。また、サイズが大きいために、開発中は、プロジェクトのビルド時間と Android Studio のプレビューの読み込み時間が増加する可能性があります。

👉 Compose のリソース  |  Jetpack Compose  |  Android Developers hatena-bookmark

サイズにも注意する必要があるようです。

 

絵柄を見ながら選択できない

これがすごく困ります。

別で、WEB画面を開くか、Android Studio の Vector Asset Tool を開くかして、絵柄を見て選択して、その名前から、サジェスチョンさせる、くらいしか方法がない。なんかいい方法あったら教えなさいよ。

Material Symbols and Icons - Google Fonts

👉 Material Symbols and Icons - Google Fonts hatena-bookmark

 Vector Asset Tool



将来的には、ライブプレビュー(今現在はリテラルのみ)ですばやく見れるようになるのかもしれません。

Android Studio Electric Eel 以降では、ライブ編集を使用して Compose の開発を高速化できます。ライブ編集は、リテラルのライブ編集をより強力にしたものです。この機能では、プレビューを自動的に更新し、コードの変更をエミュレータまたはデバイスにデプロイすることで、コンポーザブルの更新の影響をリアルタイムで確認できます。

 

👉 Compose のツール  |  Jetpack Compose  |  Android Developers hatena-bookmark

 

まとめ

将来性を見越して、ImageVector を使って


@Composable
fun LikeButton() {
  Button(onClick = {}) {
    Icon(
      imageVector = Icons.Filled.ThumbUp,
      contentDescription = null
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
  }
}

と書きたいです!

Icons.Filled.ThumbUp

ちなみに、これまでのように ベクター 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 hatena-bookmark

👉 【Jetpack Compose】Compose Settings で数分で設定画面を作る hatena-bookmark