Created
April 8, 2022 01:15
-
-
Save takahirom/620f93c0d23b11c138acc2cc4f6a2341 to your computer and use it in GitHub Desktop.
This file contains 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
// ----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