Kotlinのdata classでcopyを使うときの注意
Kotlinの data class
で copy
を使うときに気をつけないと意図しないデータ不整合が起きる可能性があります。Coroutinesを使ってると陥りやすい罠かなと思います。
現象
想定としてAndroidのComposeを考えます。他のケースでも同様です。
以下のような、Coroutinesを使ってユーザー一覧を別スレッドで取得する処理があるとします。
この処理をViewModelで以下のように取得し、UiStateを copy
を使って更新するとします。また、UiStateの別プロパティの取得処理もするとします。
この状態で、ComposeのコードからViewModelの処理を連続で呼び出します。
期待する結果としては、ユーザー一覧とフラグtrueがUiStateに設定されてることだと思います。
しかし、結果は以下のように想定しないものになります。
uiState = UiState(users=[], flag=true) <- フラグ更新後uiState = UiState(users=[User(...)], flag=false) <- ユーザー一覧取得後
最初に、フラグを更新結果がログに出力されて、次にユーザー一覧取得後の結果がログに出力されています。
しか、フラグは最初は正しいですが、ユーザー一覧取得後には元に戻ってしまっています。
原因
原因としては ユーザー一覧の取得処理です。ここでは copy
処理の中でCoroutinesの別スレッドの処理を呼び出しています。
そのため、処理前のUiStateの状態をキャプチャして、別スレッドの処理が完了後にその状態をコピーするようになっています。
そのため、この別スレッドの処理の間に何か状態が変更されたとしても、反映されないため巻き戻ってしまうことになります。
解決方法
この解決方法はいたって簡単です。 copy
処理の中で別スレッド処理をしないようにするだけです。なので、copy
前に処理するだけです。
これだけで大丈夫です。
Coroutinesが別スレッドで実行されてることを意識せずコードを書けるの非常に便利ですが、こういった罠があるため注意が必要です。