در توسعه اپلیکیشنهای اندروید، انتخاب معماری مناسب برای مدیریت وضعیت برنامه و تعاملات کاربر از اهمیت ویژهای برخوردار است. این مقاله به بررسی دو معماری پرکاربرد، یعنی MVVM (Model-View-ViewModel) و MVI (Model-View-Intent)، میپردازد و پیادهسازی آنها را با استفاده از Flow در Jetpack Compose تحلیل میکند.
در معماری MVVM، ViewModel بهعنوان واسطهای بین Model و View عمل میکند. این مؤلفه وظیفه مدیریت دادهها را بر عهده دارد و آنها را از طریق ابزارهایی مانند LiveData یا Flow به رابط کاربری (UI) منتقل میکند.
class ViewModelA : ViewModel() { private val _email = MutableStateFlow("") val email = _email.asStateFlow() private val _password = MutableStateFlow("") val password = _password.asStateFlow() fun updateEmail(email: String) { _email.update { email } } fun updatePassword(password: String) { _password.update { password } } val isEmailValid = email .map { it.isValidEmail() } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false) val isPasswordValid = password .map { it.isValidPassword() } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false) val canRegister = combine(isEmailValid, isPasswordValid) { emailValid, passwordValid -> emailValid && passwordValid }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false) }
معماری MVI بر پایه یک وضعیت (State) واحد بنا شده است که تمامی اطلاعات مربوط به View را در خود نگه میدارد. این معماری از اصل جریان یکطرفه دادهها پیروی میکند و تغییرات را بهصورت متمرکز مدیریت میکند.
data class RegisterState( val email: String = "", val password: String = "", val isEmailValid: Boolean = false, val isPasswordValid: Boolean = false, val canRegister: Boolean = false ) class ViewModelB : ViewModel() { private val _state = MutableStateFlow(RegisterState()) val state = _state.asStateFlow() fun updateEmail(email: String) { _state.update { it.copy(email = email) } } fun updatePassword(password: String) { _state.update { it.copy(password = password) } } init { state .distinctUntilChangedBy { it.email } .map { it.email.isValidEmail() } .onEach { isEmailValid -> _state.update { it.copy(isEmailValid = isEmailValid) } } .launchIn(viewModelScope) state .distinctUntilChangedBy { it.password } .map { it.password.isValidPassword() } .onEach { isPasswordValid -> _state.update { it.copy(isPasswordValid = isPasswordValid) } } .launchIn(viewModelScope) state .onEach { currentState -> _state.update { it.copy(canRegister = currentState.isEmailValid && currentState.isPasswordValid) } } .launchIn(viewModelScope) } }
state پس از پردازش مقدار ورودی به کار رفته است.viewModelScope استفاده شده است.
@Composable fun RegisterScreenA( viewModel: ViewModelA, modifier: Modifier = Modifier ) { val email by viewModel.email.collectAsState() val password by viewModel.password.collectAsState() val canRegister by viewModel.canRegister.collectAsState() // پیادهسازی رابط کاربری بر اساس این مقادیر }
@Composable fun RegisterScreenB( registerState: RegisterState, modifier: Modifier = Modifier ) { // استفاده از registerState به جای viewModel }
در این مقاله، دو معماری MVVM و MVI بررسی شدند. معماری MVVM سادهتر است و برای پروژههای کوچک و متوسط مناسب میباشد. از سوی دیگر، معماری MVI برای پروژههای بزرگ که مدیریت وضعیت پیچیدهتری دارند، انتخاب بهتری محسوب میشود. استفاده از Flow در هر دو معماری امکان مدیریت دادهها بهصورت واکنشی را فراهم میکند.
کد به صورت کامل در گیت هاب موجود(لینک زیر) است در صورتی که دوست داشتید امتیاز بدید متشکرم