<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>StateFlow</title>
	<atom:link href="https://bps-e.com/dev/tag/stateflow/feed/" rel="self" type="application/rss+xml" />
	<link>https://bps-e.com/dev</link>
	<description>android アプリ開発 kotlin + jetpack compose + material 3</description>
	<lastBuildDate>Wed, 27 Sep 2023 04:48:38 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>

<image>
	<url>https://bps-e.com/dev/wp-content/uploads/2022/10/cropped-logo3-32x32.png</url>
	<title>StateFlow</title>
	<link>https://bps-e.com/dev</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>[Android] 035. イベント消費型UIイベント(StateFlow)</title>
		<link>https://bps-e.com/dev/android-003-035/</link>
		
		<dc:creator><![CDATA[bps-e]]></dc:creator>
		<pubDate>Wed, 27 Sep 2023 04:46:21 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Giraffe]]></category>
		<category><![CDATA[Jetpack Compose]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[StateFlow]]></category>
		<guid isPermaLink="false">https://bps-e.com/dev/?p=1089</guid>

					<description><![CDATA[発生したイベントをキューに貯めて順次処理して行きたい場合でViewModelを使用時の使えそうな実装パターンとしてイベント消費型UIイベントがあります デベロッパーの説明だけでは足らない気もするので対応してみます以下のサ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>発生したイベントをキューに貯めて順次処理して行きたい場合でViewModelを使用時の使えそうな実装パターンとしてイベント消費型UIイベントがあります</p>



<p>デベロッパーの説明だけでは足らない気もするので対応してみます<br>以下のサイトの内容の改造版みたいな感じです<br><a rel="noopener" href="https://star-zero.medium.com/viewmodel%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E5%AE%9F%E8%A3%85-74dd814deb97" target="_blank">https://star-zero.medium.com/viewmodel%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E5%AE%9F%E8%A3%85-74dd814deb97</a></p>



<p>デベロッパーの説明<br><a href="https://developer.android.com/topic/architecture/ui-layer/events?hl=ja&amp;authuser=1#consuming-trigger-updates">https://developer.android.com/topic/architecture/ui-layer/events?hl=ja&amp;authuser=1#consuming-trigger-updates</a></p>



<div style="height:var(--wp--preset--spacing--50)" aria-hidden="true" class="wp-block-spacer"></div>



<p>Eventクラスは消費時に判別するためのユニークなIDをつけます<br>ダミーのイベント発生のstubとイベント消費のためのconsumeEventを実装します</p>



<p>ダミーのイベントはテストのため連続で５つ発生するようにしてます</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-kt" data-lang="Kotlin"><code>@Stable
sealed class Event {
    val id = UUID.randomUUID().toString()
    data class Message(val message: String) : Event()
}

class AppViewModel : ViewModel() {
    private val _uiEvents = MutableStateFlow&lt;List&lt;Event&gt;&gt;(emptyList())
    val uiEvents = _uiEvents.asStateFlow()

    fun stub() = viewModelScope.launch {
        val message = listOf(
            &quot;おはよう&quot;,
            &quot;こんにちわ&quot;,
            &quot;こんばんわ&quot;,
        )

        repeat(5) {
            val msg = message.random()
            _uiEvents.update {
                it + Event.Message(msg)
            }
        }
    }

    fun consumeEvent(event: Event) {
        _uiEvents.update {
            e -&gt; e.filterNot { it.id == event.id }
        }
    }
}</code></pre></div>



<p>LaunchedEffectでuiEventsに変化(追加/消費)が発生した時に最初に追加されたイベントを1つ取得して処理していきます<br>ここではイベント発生後の処理の完了を待つ変わりにdelayしてます</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-kt" data-lang="Kotlin"><code>@Composable
fun AppContent(viewModel: AppViewModel = viewModel()) {
    val uiEvents by viewModel.uiEvents.collectAsState()
    var message by remember { mutableStateOf(&quot;&quot;) }

    LaunchedEffect(uiEvents) {
        if (uiEvents.isNotEmpty()) {
            when (val event = uiEvents.first()) {
                is Event.Message -&gt; {
                    message = &quot;${event.message}(${event.id})&quot;
                    Log.d(&quot;App&quot;, message)
                    launch {
                        delay(1_000)
                        viewModel.consumeEvent(event)
                    }
                }
            }
        }
    }

    Column {
        Button(onClick = { viewModel.stub() }) {
            Text(&quot;Start&quot;)
        }
        Text(message)
    }
}</code></pre></div>



<div style="height:var(--wp--preset--spacing--50)" aria-hidden="true" class="wp-block-spacer"></div>



<p>古典的なやり方だとキュークラス実装したり再起処理実装したりとごちゃごちゃやってたけど簡単にスッキリとした実装となりました</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="has-text-align-right">Android Studio Giraffe 2022.3.1 built on June 29, 2023</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>[Android] 025. Flow</title>
		<link>https://bps-e.com/dev/android-003-025/</link>
		
		<dc:creator><![CDATA[bps-e]]></dc:creator>
		<pubDate>Thu, 31 Aug 2023 19:48:01 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Giraffe]]></category>
		<category><![CDATA[Jetpack Compose]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Flow]]></category>
		<category><![CDATA[StateFlow]]></category>
		<guid isPermaLink="false">https://bps-e.com/dev/?p=888</guid>

					<description><![CDATA[わかりやすい説明してくれている人たくさんいるのでとりあえず自分向けのメモ書きレベル Flow developerの説明は以下https://developer.android.com/kotlin/flow?hl=ja  [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>わかりやすい説明してくれている人たくさんいるのでとりあえず自分向けのメモ書きレベル</p>



<h2 class="wp-block-heading"><span id="toc1">Flow</span></h2>



<p>developerの説明は以下<br><a rel="noopener" href="https://developer.android.com/kotlin/flow?hl=ja" target="_blank">https://developer.android.com/kotlin/flow?hl=ja</a></p>



<p>とりあえずここらへん見ればなんとなく理解できます<br><a rel="noopener" href="https://speakerdeck.com/sys1yagi/5fen-tewakarukotlin-coroutines-flow" target="_blank">https://speakerdeck.com/sys1yagi/5fen-tewakarukotlin-coroutines-flow</a><br><a rel="noopener" href="https://qiita.com/mi_iroha/items/78721a53cb113a82a1b1" target="_blank">https://qiita.com/mi_iroha/items/78721a53cb113a82a1b1</a></p>



<p>ざっくり言うと&#8230;</p>



<p>・Flowはコルーチンの一種でコルーチンにはワンショット/ホットストリーム/コールドストリームがあるがFlowはコールドストリーム</p>



<p>・ワンショット<br>コルーチンを一度だけ実行し再利用できない</p>



<p>・ホットストリーム<br>常に定期的なデータの生成や更新が行われる</p>



<p>・コールドストリーム<br>要求があるまでデータを生成しない</p>



<figure class="wp-block-table"><table><tbody><tr><td>ワンショット</td><td>launch, Job</td><td>戻値なし</td></tr><tr><td>ワンショット</td><td>async, Deferred</td><td>戻値あり</td></tr><tr><td>ホットストリーム</td><td>Channel, (StateFlow / SharedFlow)</td><td>複数の値</td></tr><tr><td>コールドストリーム</td><td>Flow</td><td>複数の値</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><span id="toc2">StateFlow / SharedFlow</span></h2>



<p>StateFlowはSharedFlowのサブクラスでSharedFlowは複数箇所でのSubscribeでデータや状態を共有できるFlow、StateFlowは状態保持に特化したSharedFlowでLiveDataに似た機能です</p>



<p>developerの説明は以下<br><a rel="noopener" href="https://developer.android.com/kotlin/flow/stateflow-and-sharedflow?hl=ja" target="_blank">https://developer.android.com/kotlin/flow/stateflow-and-sharedflow?hl=ja</a></p>



<p>ここらへんが参考になるかも<br><a rel="noopener" href="https://at-sushi.work/blog/24/" target="_blank">https://at-sushi.work/blog/24/</a></p>



<div style="height:var(--wp--preset--spacing--50)" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc3">StateFlow / MutableStateFlow</span></h3>



<p>FlowをStateFlowに変換するにはstateInを使います<br>StateFlowにすることでホットストリーム化します</p>



<p>stateInの引数のstartedに指定するSharingStartedについては以下にわかりやすい説明がありましたので引用します</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>SharingStartedとは stateIn()の第二引数にはSharingStartedを指定します。<br>このSharingStartedとは、共有コルーチンを開始、および終了させるためのストラテジーであるとドキュメントでは説明されています。<br>組み込みストラテジーのセットとしてEagerly、Lazily、WhileSubscribedの3つのストラテジーが提供されています。 </p>



<p>SharingStarted.Eagerlyとは SharingStarted.Eagerlyを指定した場合は、stateIn()を呼び出したタイミングで値の生成を開始します。注意点としてはコンシューマー側でcollectAsState()を呼び出したタイミングによって、最初にemit()された値などを取得できない可能性があります。 </p>



<p>SharingStarted.Lazlyとは SharingStarted.Lazylyを指定した場合は、最初にコンシューマー側によってcollectAsState()が呼び出されたタイミングで値を生成します。これにより、最初に取得しようとしたコンシューマーは今までに発行されたすべての値を取得することが保証されます。 </p>



<p>SharingStarted.WhileSubscribedとは SharingStarted.WhileSubscribedは、最初にコンシューマー側によってcollectAsState()が呼び出されたタイミングで値を生成します。しかし他のオプションと違い、cancel()などが呼び出されることにより、値を必要としているコンシューマー側の数が0になった時点で値の生成を辞めますので注意が必要です。</p>
<cite><a rel="noopener" href="https://qiita.com/takagimeow/items/2271c8a843b8caf92ebe" target="_blank">https://qiita.com/takagimeow/items/2271c8a843b8caf92ebe</a></cite></blockquote>



<p>仕様は以下で確認<br><a rel="noopener" href="https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-sharing-started/-companion/" target="_blank">https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-sharing-started/-companion/</a></p>



<p>Roomの記事でSharingStarted.WhileSubscribedの引数がなぜ5000なのかはdeveloper blogにありました</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>ほとんどの場合、最後のコレクターが消失した後、さらに 5 秒間上流フローをアクティブに維持します。これにより、構成変更などの特定の状況でアップストリーム フローが再起動されるのを回避できます。このヒントは、アップストリーム フローの作成にコストがかかる場合、およびこれらの演算子が ViewModel で使用される場合に特に役立ちます。</p>
<cite><a rel="noopener" href="https://medium.com/androiddevelopers/things-to-know-about-flows-sharein-and-statein-operators-20e6ccb2bc74" target="_blank">https://medium.com/androiddevelopers/things-to-know-about-flows-sharein-and-statein-operators-20e6ccb2bc74</a></cite></blockquote>



<div style="height:var(--wp--preset--spacing--50)" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc4">SharedFlow / MutableSharedFlow</span></h3>



<p>FlowをStateFlowに変換するにはshardInを使います</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="has-text-align-right">Android Studio Giraffe 2022.3.1 Patch 1 built on August 17, 2023</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>[Android] 018. Room(DB)</title>
		<link>https://bps-e.com/dev/android-018/</link>
		
		<dc:creator><![CDATA[bps-e]]></dc:creator>
		<pubDate>Thu, 10 Nov 2022 15:30:17 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Jetpack Compose]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Material 3]]></category>
		<category><![CDATA[Flow]]></category>
		<category><![CDATA[Room]]></category>
		<category><![CDATA[StateFlow]]></category>
		<guid isPermaLink="false">https://bps-e.com/dev/?p=110</guid>

					<description><![CDATA[Roomを使用してローカルデータベースを扱う 以下が参考になるかもですhttps://developer.android.com/training/data-storage/room?hl=ja 設定 Project S [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Roomを使用してローカルデータベースを扱う</p>



<p>以下が参考になるかもです<br><a rel="noopener" href="https://developer.android.com/training/data-storage/room?hl=ja" target="_blank">https://developer.android.com/training/data-storage/room?hl=ja</a></p>



<h2 class="wp-block-heading"><span id="toc1">設定</span></h2>



<h3 class="wp-block-heading"><span id="toc2">Project Structure</span></h3>



<p>androidx.room:room-ktxなど最新バージョンを確認してVariablesでroom_versionを追加する<br>room_version 2.4.3</p>



<p>以下のライブラリをroom_versionで追加<br>androidx.room:room-ktx<br>androidx.room:room-runtime<br>androidx.room:room-compiler</p>



<h3 class="wp-block-heading"><span id="toc3">ksp</span></h3>



<p>使用しているKotlinのバージョンにあった設定をする</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain" data-file="build.gradle(Project)"><code>buildscript {
    ext {
        room_version = &#39;2.4.3&#39;
    }
}
plugins {
    id &#39;com.google.devtools.ksp&#39; version &#39;1.7.20-1.0.7&#39; apply false
}</code></pre></div>



<p>pluginsにid &#8216;com.google.devtools.ksp&#8217; を追加<br>androidx.room:room-compilerのimplementationをkspに変更</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain" data-file="build.gradle(Module)"><code>plugins {
    id &#39;com.google.devtools.ksp&#39;
}
dependencies {
    implementation &quot;androidx.room:room-ktx:$room_version&quot;
    implementation &quot;androidx.room:room-runtime:$room_version&quot;
    ksp &quot;androidx.room:room-compiler:$room_version&quot;
}</code></pre></div>



<h2 class="wp-block-heading"><span id="toc4">実装</span></h2>



<p>Flow / StateFlow を使用したRoomの実装例です</p>



<p>clickボタンを押すとname = &#8220;test_(押した回数)&#8221;とnum = ランダム(0-99)がDBに追加されてリストに表示されます</p>



<p>まずDBで使用するテーブルをdata classで、次にDAO(Data Access Object)を作成<br>RoomDatabaseの定義、DB操作のRepository、ViewModelを作成してます</p>



<p>RoomDatabaseにApplicationContextを渡す必要があるためAndroidViewModelにしています</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-kt" data-lang="Kotlin"><code>@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    val datasList = viewModel.datasList.collectAsState()
    var count: Int by rememberSaveable { mutableStateOf( 0) }

    MaterialTheme {
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
            Column {
                Row(modifier = Modifier.padding(4.dp)) {
                    Button(onClick = {
                        val name = &quot;test_${++count}&quot;
                        if (datasList.value.find { it.name == name } == null) {
                            viewModel.insert(Datas(name, SecureRandom().nextInt(100)))
                        }
                        else {
                            viewModel.update(Datas(name, SecureRandom().nextInt(100)))
                        }
                    }) {
                        Text(&quot;click&quot;)
                    }

                    Button(onClick = { viewModel.deleteAll() }) {
                        Text(&quot;clear&quot;)
                    }
                }

                datasList.value?.let { datas -&gt;
                    LazyColumn {
                        items(datas) { item -&gt;
                            Text(&quot;${item.name} ${item.num}&quot;)
                        }
                    }
                }
            }
        }
    }
}

@Entity(tableName = &quot;datas_table&quot;)
data class Datas(
    @PrimaryKey @ColumnInfo(name = &quot;name&quot;) var name: String = &quot;&quot;,
    @ColumnInfo(name = &quot;num&quot;) var num: Int = 0,
)

@Dao interface DatasDao {
    @Query(&quot;SELECT * FROM datas_table ORDER BY name ASC&quot;)
    fun getAlphabetizedDatasList(): Flow&lt;List&lt;Datas&gt;&gt;

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insert(datas: Datas)

    @Update(onConflict = OnConflictStrategy.REPLACE)
    suspend fun update(datas: Datas)

    @Query(&quot;DELETE FROM datas_table&quot;)
    suspend fun deleteAll()
}

@Database(entities = [Datas::class], version = 1, exportSchema = false)
abstract class DatasRoomDatabase : RoomDatabase() {
    abstract fun dao(): DatasDao

    companion object {
        @Volatile private var INSTANCE: DatasRoomDatabase? = null

        fun getDatabase(context: Context): DatasRoomDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    DatasRoomDatabase::class.java,
                    &quot;app_database&quot;
                ).build()
                INSTANCE = instance
                // return instance
                instance
            }
        }
    }
}

class DatasRepository(
    application: Application,
    private val db: DatasRoomDatabase = DatasRoomDatabase.getDatabase(application),
    private val dao: DatasDao = db.dao()
) {
    val datasList = dao.getAlphabetizedDatasList()

    // ワーカースレッド以外で使用した場合警告
    @Suppress(&quot;RedundantSuspendModifier&quot;)
    @WorkerThread
    suspend fun insert(datas: Datas) {
        dao.insert(datas)
    }
    @Suppress(&quot;RedundantSuspendModifier&quot;)
    @WorkerThread
    suspend fun update(datas: Datas) {
        dao.update(datas)
    }
    @Suppress(&quot;RedundantSuspendModifier&quot;)
    @WorkerThread
    suspend fun deleteAll() {
        dao.deleteAll()
    }
}

class MainViewModel(
    application: Application
) : AndroidViewModel(application) {
    private val repo: DatasRepository = DatasRepository(getApplication())
    val datasList: StateFlow&lt;List&lt;Datas&gt;&gt; = repo.datasList.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = listOf()
    )

    fun insert(datas: Datas) = viewModelScope.launch {
        repo.insert(datas)
    }
    fun update(datas: Datas) = viewModelScope.launch {
        repo.update(datas)
    }
    fun deleteAll() = viewModelScope.launch {
        repo.deleteAll()
    }
}</code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="has-text-align-right">Android Studio Dolphin 2021.3.1 Patch 1 built on September 30, 2022</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>[Android] 011. ViewModelの状態</title>
		<link>https://bps-e.com/dev/android-011/</link>
		
		<dc:creator><![CDATA[bps-e]]></dc:creator>
		<pubDate>Fri, 28 Oct 2022 22:00:15 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Jetpack Compose]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[LiveData]]></category>
		<category><![CDATA[SavedStateHandle]]></category>
		<category><![CDATA[State]]></category>
		<category><![CDATA[StateFlow]]></category>
		<category><![CDATA[ViewModel]]></category>
		<guid isPermaLink="false">https://bps-e.com/dev/?p=202</guid>

					<description><![CDATA[ViewModelの状態 data classに定義している値の状態を監視しますButtonをクリックするとTextが更新されます State SavedStateHandle rememberSaveableと同等にす [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading"><span id="toc1">ViewModelの状態</span></h2>



<p>data classに定義している値の状態を監視します<br>ButtonをクリックするとTextが更新されます</p>



<h3 class="wp-block-heading"><span id="toc2">State</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-kt" data-lang="Kotlin"><code>// numはダミーで使いません
data class Datas(var name: String = &quot;&quot;, var num: Int = 0)
class MainViewModel : ViewModel() {
    var datas by mutableStateOf(Datas(&quot;none&quot;))
        private set

    fun setName(name: String) {
        datas = datas.copy(name = name)
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            Column {
                Text(viewModel.datas.name)
                Button(onClick = { viewModel.setName(&quot;test&quot;) }) {
                    Text(&quot;click&quot;)
                }
            }
        }
    }
}</code></pre></div>



<h3 class="wp-block-heading"><span id="toc3">SavedStateHandle</span></h3>



<p>rememberSaveableと同等にするにはSavedStateHandleを使います</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-kt" data-lang="Kotlin"><code>class MainViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    var datas: Datas by savedStateHandle.saveable { mutableStateOf(Datas(&quot;none&quot;)) }
        private set

    fun setName(name: String) {
        datas = datas.copy(name = name)
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            Column {
                Text(viewModel.datas.name)
                Button(onClick = { viewModel.setName(&quot;test&quot;) }) {
                    Text(&quot;click&quot;)
                }
            }
        }
    }
}</code></pre></div>



<h3 class="wp-block-heading"><span id="toc4">LiveData</span></h3>



<p>LiveDataを使うために以下をProject Structureで追加します<br>androidx.compose.runtime:runtime-livedata</p>



<p>LiveDataはJetpack Composeではいずれ使われなくなっていくと思います</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-kt" data-lang="Kotlin"><code>class MainViewModel() : ViewModel() {
    var datas: MutableLiveData&lt;Datas&gt; = MutableLiveData()
        private set

    fun setName(name: String) {
        // datas.value?.copy(name = name) はできません
        datas.value = Datas(name)
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            val datas: Datas by viewModel.datas.observeAsState(Datas(&quot;none&quot;))

            Column {
                Text(datas.name)
                Button(onClick = { viewModel.setName(&quot;test&quot;) }) {
                    Text(&quot;click&quot;)
                }
            }
        }
    }
}</code></pre></div>



<h3 class="wp-block-heading"><span id="toc5">StateFlow</span></h3>



<p>Activity側でcollectAsStateを呼び出す必要があります<br>今回の要件ではStateFlowを使う意味はあまりありませんがFlowを扱う実装時に使うことになります</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-kt" data-lang="Kotlin"><code>class MainViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    var datas = MutableStateFlow&lt;Datas&gt;(Datas(&quot;none&quot;))
        private set

    fun setName(name: String) {
        //datas.value = datas.value.copy(name = name)
        datas.update { datas.value.copy(name = name) }
    }
}

@Composable fun AppContent(viewModel: MainViewModel = viewModel()) {
    MaterialTheme {
        Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
            val datas = viewModel.datas.collectAsState()

            Column {
                Text(datas.value.name)
                Button(onClick = { viewModel.setName(&quot;test&quot;) }) {
                    Text(&quot;click&quot;)
                }
            }
        }
    }
}</code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="has-text-align-right">Android Studio Dolphin 2021.3.1 Patch 1 built on September 30, 2022</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
