Skip to content

Instantly share code, notes, and snippets.

@takahirom
Created April 8, 2022 01:15
Show Gist options
  • Save takahirom/620f93c0d23b11c138acc2cc4f6a2341 to your computer and use it in GitHub Desktop.
Save takahirom/620f93c0d23b11c138acc2cc4f6a2341 to your computer and use it in GitHub Desktop.
// ----UI Layer----
// -UI Layer(UI element)-
@AndroidEntryPoint
class ArticlesActivity : AppCompatActivity() {
// UI 1. ✅ You shouldn't store or keep in memory any application
// data or state in your app components
lateinit var binding: ActivityArticlesBinding
private val articlesViewModel by viewModels<ArticlesViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityArticlesBinding.inflate(layoutInflater)
setContentView(binding.root)
// UI 2. ✅ Make sure you take the lifecycle of the UI into consideration
lifecycleScope.launch {
articlesViewModel
.uiState
.flowWithLifecycle(lifecycle)
.collect { uiState ->
applyUiState(uiState)
}
}
binding.refreshButton.setOnClickListener {
articlesViewModel.onRefresh()
}
}
// UI 3. ✅ You should drive your UI from data models
private fun applyUiState(uiState: ArticlesUiState) {
binding.articles.text = uiState
.articles
.joinToString("\n") { it.author + ":" + it.title }
}
}
// -UI Layer(state holder (ViewModel))-
// UI 4. ✅ Define UI state
data class ArticlesUiState(
// UI 5. ✅ Immutability
val articles: List<Article>
)
@HiltViewModel
class ArticlesViewModel @Inject constructor(
private val getArticlesUseCase: GetArticlesUseCase
) : ViewModel() {
// UI 6. ✅ Use unidirectional data flow
// The pattern where the state flows down and the events flow up is called a unidirectional data flow (UDF).
// The uiState is state
// The onRefresh is event
private val _uiState = MutableStateFlow(ArticlesUiState(listOf()))
// UI 7. ✅ Expose UI state
// UI 8. ✅ As business logic gets more complex, having a singular UiState class where all properties are immediately available becomes increasingly important
// UI 9. ✅ You should expose the UI state in an observable data holder like LiveData or StateFlow
val uiState get() = _uiState.asStateFlow()
init {
viewModelScope.launch {
val articles = getArticlesUseCase()
_uiState.update { currentUiState: ArticlesUiState ->
currentUiState.copy(
articles = articles
)
}
}
}
// UI 10. ✅ Any work performed in a ViewModel should be main-safe—safe to call from the main thread.
fun onRefresh() {
viewModelScope.launch {
val articles = getArticlesUseCase()
_uiState.update { currentUiState ->
currentUiState.copy(
articles = articles
)
}
}
}
}
private fun <T> MutableStateFlow<T>.update(function: (currentUiState: T) -> T) {
value = function(value)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment