Sobes.tech
Middle+

Hoe zou u zelfstandig een MVVM-architectuur aanpak implementeren?

sobes.tech AI

Antwoord van AI

MVVM (Model-View-ViewModel) is een architectuurpatroon dat de UI, presentatie-logica en bedrijfslogica scheidt.

Belangrijke componenten:

  • Model: Vertegenwoordigt gegevens en bedrijfslogica. Afhankelijk van de UI niet.
  • View: UI-laag. Toont gegevens uit ViewModel en stuurt gebruikersacties (gebeurtenissen) naar ViewModel. Bevat geen bedrijfslogica.
  • ViewModel: Bevat presentatie-logica, bereidt gegevens uit Model voor weergave in View en verwerkt gebruikersacties. Heeft geen directe verwijzingen naar View, interacteert via observeerbare gegevens (Observable streams).

Zelfstandige implementatie:

  1. Model maken: Eenvoudige Plain Old Java Objects (POJO) of Kotlin data classes voor gegevensrepresentatie, repositories voor toegang tot gegevensbronnen (netwerk, database).

    // Voorbeeld Model
    data class User(val id: Int, val name: String, val email: String)
    
    class UserRepository {
        fun getUser(userId: Int): User {
            // Logica om gebruiker op te halen uit gegevensbron
            return User(userId, "Test User $userId", "test$userId@example.com")
        }
    }
    
  2. ViewModel maken: Klasse die erft van ViewModel uit Android Architecture Components (of eigen implementatie met Lifecycle awareness). Bevat LiveData of Kotlin StateFlow/SharedFlow voor observeerbare gegevens. Heeft methoden voor verwerking van gebruikersacties en gegevensupdate.

    // Voorbeeld ViewModel
    class UserViewModel(private val userRepository: UserRepository) : androidx.lifecycle.ViewModel() {
    
        private val _user = MutableLiveData<User>()
        val user: LiveData<User> = _user
    
        fun loadUser(userId: Int) {
            // In een echte app - asynchrone loading
            val loadedUser = userRepository.getUser(userId)
            _user.value = loadedUser // LiveData bijwerken
        }
    
        fun updateUser(newUser: User) {
            // Logica voor bijwerken gebruiker
            _user.value = newUser
        }
    }
    
  3. View implementeren: Activity of Fragment. Verbindt met ViewModel, abonneert zich op observeerbare gegevens uit ViewModel, en werkt UI bij dat gegevens veranderen. Delegeert gebruikersgebeurtenissen (klikken, tekst invoeren) aan ViewModel. Gebruikt Data Binding of View Binding voor meer declaratieve binding.

    // View (Fragment) voorbeeld
    class UserFragment : Fragment() {
    
        private lateinit var viewModel: UserViewModel
        private var _binding: FragmentUserBinding? = null
        private val binding get() = _binding!!
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            _binding = FragmentUserBinding.inflate(inflater, container, false)
            return binding.root
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            // Verkrijg ViewModel, bij voorkeur via ViewModelProvider
            viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
    
            // Abonneer op observeerbare gegevens
            viewModel.user.observe(viewLifecycleOwner) { user ->
                // UI bijwerken bij verandering gebruiker
                binding.userNameTextView.text = user.name
                binding.userEmailTextView.text = user.email
            }
    
            // Gebeurtenis delegatie naar ViewModel
            binding.loadUserButton.setOnClickListener {
                viewModel.loadUser(1) // Voorbeeld: laden gebruiker met ID 1
            }
        }
    
        override fun onDestroyView() {
            super.onDestroyView()
            _binding = null
        }
    }
    
  4. Componenten koppelen: View maakt een instantie van ViewModel (via ViewModelProvider) en abonneert zich op de observeerbare gegevens. ViewModel werkt met Model.

Belangrijke aspecten van zelfstandige implementatie:

  • Gebruik van LiveData of Flow voor reactiviteit en automatische UI-updates bij gegevenswijzigingen.
  • Gebruik van ViewModelProvider voor correcte levenscyclusbeheer van ViewModel.
  • Gebruik van Dependency Injection (bijvoorbeeld Hilt of Koin) voor het leveren van afhankelijkheden (bijvoorbeeld UserRepository) aan ViewModel.
  • Afhandelen van asynchrone operaties (netwerkverzoeken, werken met database) in ViewModel met behulp van coroutines of andere mechanismen.

Voordelen van deze aanpak:

  • Testbaarheid: ViewModel kan gemakkelijk afzonderlijk van UI worden getest.
  • Verantwoordelijkheden scheiding: Duidelijke scheiding tussen UI, presentatie-logica en bedrijfslogica.
  • Robuustheid bij configuratiewijzigingen: ViewModel wordt bewaard bij schermrotaties en andere configuratiewijzigingen.
  • Verbeterde onderhoudbaarheid van code.