(本当は Compose のコード例(State/MutableState)にしたかったんだけど、まだ Jetpack Compose は Kotlin 1.5 に対応してないので sealed interface 使えないんだよね...)
ViewModel で持ってる LiveData を Activity で observe してるとする。
- class MainActivity : AppCompatActivity() {
-
- private val viewModel: MainViewModel by viewModels()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
-
- viewModel.state.observe(this) {
- when (it) {
- is State.Data -> {
- println(it.value)
- }
- State.Loading -> {
-
- }
- }
- }
- }
- }
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.state.observe(this) {
when (it) {
is State.Data -> {
println(it.value)
}
State.Loading -> {
}
}
}
}
}
- class MainViewModel : ViewModel() {
-
- private val _state = MutableLiveData<State>()
- val state: LiveData<State>
- get() = _state
-
- fun doSomething() {
- val state = _state.value
- if (state is State.Data) {
- state.mutableValue = Random.nextInt()
- }
- }
- }
-
- sealed class State {
- object Loading : State()
-
- data class Data(val id: String) : State() {
-
-
- var mutableValue: Int = -1
-
- val value: Int
- get() = mutableValue
- }
- }
class MainViewModel : ViewModel() {
private val _state = MutableLiveData<State>()
val state: LiveData<State>
get() = _state
fun doSomething() {
val state = _state.value
if (state is State.Data) {
state.mutableValue = Random.nextInt()
}
}
}
sealed class State {
object Loading : State()
data class Data(val id: String) : State() {
// 変更できるのは MainViewModel からだけにしたいが、
// private にすると MainViewModel からも見えなくなる
var mutableValue: Int = -1
val value: Int
get() = mutableValue
}
}
↑ State.Data が持つ mutableValue は MainViewModel からのみ変更できるようにしたい。
mutableValue に private は MainViewModel から見えなくなるのでダメ。
- private var mutableValue: Int = -1
private var mutableValue: Int = -1
これもダメ。
- private sealed class State {
private sealed class State {
- private data class Data(val id: String) : State() {
private data class Data(val id: String) : State() {
Data を top level にすると private をつけても MainViewModel から見えるけど、MainActivity から見えなくなるのでダメ。
- sealed class State
-
- object Loading : State()
-
-
-
- private data class Data(val id: String) : State() {
- var mutableValue: Int = -1
-
- val value: Int
- get() = mutableValue
- }
sealed class State
object Loading : State()
// MainViewModel から mutableValue は見えるが
// Data が MainActivity からは見えなくなる
private data class Data(val id: String) : State() {
var mutableValue: Int = -1
val value: Int
get() = mutableValue
}
ということで sealed interface を使います。
- class MainViewModel : ViewModel() {
-
- private val _state = MutableLiveData<State>()
- val state: LiveData<State>
- get() = _state
-
- fun doSomething() {
- val state = _state.value
- if (state is DataImpl) {
- state.mutableValue = Random.nextInt()
- }
- }
- }
-
- sealed interface State
-
- object Loading : State
-
- sealed interface Data : State {
- val value: Int
- }
-
- private class DataImpl(val id: Int) : Data {
-
- var mutableValue: Int = id
-
- override val value: Int
- get() = mutableValue
- }
class MainViewModel : ViewModel() {
private val _state = MutableLiveData<State>()
val state: LiveData<State>
get() = _state
fun doSomething() {
val state = _state.value
if (state is DataImpl) {
state.mutableValue = Random.nextInt()
}
}
}
sealed interface State
object Loading : State
sealed interface Data : State {
val value: Int
}
private class DataImpl(val id: Int) : Data {
// private class なので変更できるのは同じファイルからだけ
var mutableValue: Int = id
override val value: Int
get() = mutableValue
}