Last active
May 13, 2020 11:46
-
-
Save osipxd/bb5aee5fb2aec77f4a0e9af33fa089fa to your computer and use it in GitHub Desktop.
Partial view state rendering with LiveData transformations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DetailsFragment : BaseFragment(R.layout.fragment_details) { | |
lateinit val viewModel: DetailsViewModel | |
// ... | |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
super.onVewCreated(view, savedInstanceState) | |
// Assumed that viewModel initialized here | |
observe(viewModel.title, ::renderTitle) | |
observe(viewModel.description, ::renderDescription) | |
} | |
private fun renderTitle(title: String) { | |
setTitleText(title) | |
} | |
private fun renderDescription(description: String) { | |
setDescriptionText(state.description) | |
} | |
// ... | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DetailsViewModel : ViewModel() { | |
// "Source of truth" LiveData | |
private val liveState = MutableLiveData<DetailsViewState>(createInitialState()) | |
// State representations | |
val title: LiveData<String> = liveState.mapDistinct { "${it.title} ${it.number}" } | |
val description: LiveData<String> = liveState.mapDistinct { it.description } | |
// Delegate for easier work with state inside LiveData | |
private var state: DetailsViewState by liveState.delegate() | |
private fun createInitialState(): DetailsViewState { | |
return DetailsViewState(title = "None", description = "None") | |
} | |
fun onUpdateRequested() { | |
state = state.copy(title = "New Title") | |
} | |
// ... | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data class DetailsViewState( | |
val title: String, | |
val description: String, | |
val number: Int | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.lifecycle.LiveData | |
import androidx.lifecycle.MutableLiveData | |
import androidx.lifecycle.distinctUntilChanged | |
import androidx.lifecycle.map | |
/** | |
* Sequential call of [map] and [distinctUntilChanged] in one function. | |
* Requires `androidx.lifecycle:lifecycle-livedata-ktx` dependency | |
*/ | |
inline fun <X, Y> LiveData<X>.mapDistinct(crossinline transform: (X) -> Y): LiveData<Y> { | |
return map(transform).distinctUntilChanged() | |
} | |
/** | |
* Delegate for easier work with [MutableLiveData] content. | |
* | |
* It is shortest version of: | |
* ``` | |
* val liveState = MutableLiveData<IntroViewState>(initialState) | |
* var state: IntroViewState | |
* get() = liveState.requireValue() | |
* set(value) = liveState.onNext(value) | |
* ``` | |
* With delegate you can replace it with next code: | |
* ``` | |
* val liveState = MutableLiveData<IntroViewState>(initialState) | |
* var state: IntroViewState by liveState.delegate() | |
* ``` | |
*/ | |
fun <T : Any> MutableLiveData<T>.delegate(): ReadWriteProperty<Any, T> { | |
return object : ReadWriteProperty<Any, T> { | |
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) = onNext(value) | |
override fun getValue(thisRef: Any, property: KProperty<*>): T = requireValue() | |
} | |
} | |
fun <T> MutableLiveData<T>.onNext(next: T) { | |
this.value = next | |
} | |
fun <T : Any> LiveData<T>.requireValue(): T = checkNotNull(value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment