Sobes.tech
Middle+

Kako biste sami implementirali arhitektonski pristup MVVM?

sobes.tech АИ

Одговор од АИ

MVVM (Model-View-ViewModel) je arhitektonski obrazac koji razdvaja UI, logiku prikaza i poslovnu logiku.

Glavne komponente:

  • Model: Predstavlja podatke i poslovnu logiku. Ne zavisi od UI.
  • View: UI sloj. Prikazuje podatke iz ViewModel-a i šalje akcije korisnika (događaje) u ViewModel. Ne sadrži poslovnu logiku.
  • ViewModel: Sadrži logiku prikaza, priprema podatke iz Model-a za prikaz u View i obrađuje akcije korisnika. Nema direktne veze sa View, komunicira putem posmatranih podataka (Observable streams).

Samostalna implementacija:

  1. Kreiranje Model-a: Jednostavni Plain Old Java Objects (POJO) ili Kotlin data klase za predstavljanje podataka, repozitoriji za pristup izvorima podataka (mreža, baza podataka).

    // Primer Model-a
    data class User(val id: Int, val name: String, val email: String)
    
    class UserRepository {
        fun getUser(userId: Int): User {
            // Logika za dobijanje korisnika iz izvora podataka
            return User(userId, "Test User $userId", "test$userId@example.com")
        }
    }
    
  2. Kreiranje ViewModel-a: Klasa koja nasleđuje od ViewModel iz Android Architecture Components (ili sopstvena implementacija sa Lifecycle awareness). Čuva LiveData ili Kotlin StateFlow/SharedFlow za posmatrane podatke. Sadrži metode za obradu akcija korisnika i ažuriranje podataka.

    // Primer ViewModel-a
    class UserViewModel(private val userRepository: UserRepository) : androidx.lifecycle.ViewModel() {
    
        private val _user = MutableLiveData<User>()
        val user: LiveData<User> = _user
    
        fun loadUser(userId: Int) {
            // U pravoj aplikaciji - asinhrono učitavanje
            val loadedUser = userRepository.getUser(userId)
            _user.value = loadedUser // Ažuriranje LiveData
        }
    
        fun updateUser(newUser: User) {
            // Logika za ažuriranje korisnika
            _user.value = newUser
        }
    }
    
  3. Implementacija View: Activity ili Fragment. Povezuje se sa ViewModel-om, pretplaćuje se na posmatrane podatke iz ViewModel-a, ažurira UI pri promeni podataka. Delegira obradu događaja korisnika (klikovi, unos teksta) u ViewModel. Koristi Data Binding ili View Binding za deklarativniju vezu.

    // Primer View (Fragment)
    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)
    
            // Dobijanje ViewModel-a, po želji putem ViewModelProvider
            viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
    
            // Pretplata na posmatrane podatke
            viewModel.user.observe(viewLifecycleOwner) { user ->
                // Ažuriranje UI pri promeni korisnika
                binding.userNameTextView.text = user.name
                binding.userEmailTextView.text = user.email
            }
    
            // Delegiranje događaja u ViewModel
            binding.loadUserButton.setOnClickListener {
                viewModel.loadUser(1) // Primer: učitavanje korisnika sa ID 1
            }
        }
    
        override fun onDestroyView() {
            super.onDestroyView()
            _binding = null
        }
    }
    
  4. Povezivanje komponenti: View kreira instancu ViewModel-a (kroz ViewModelProvider) i pretplaćuje se na njena posmatrana stanja. ViewModel radi sa Model-om.

Ključni aspekti samostalne implementacije:

  • Korišćenje LiveData ili Flow za reaktivnost i automatsko osvežavanje UI pri promeni podataka.
  • Korišćenje ViewModelProvider za obezbeđivanje ispravnog životnog ciklusa ViewModel-a.
  • Korišćenje Dependency Injection (npr. Hilt ili Koin) za obezbeđivanje zavisnosti (npr. UserRepository) u ViewModel.
  • Obrada asinhronih operacija (mrežni zahtevi, rad sa bazom podataka) u ViewModel-u koristeći korutine ili druge mehanizme.

Prednosti takvog pristupa:

  • Testabilnost: ViewModel se lako može testirati odvojeno od UI.
  • Razdvajanje odgovornosti: Jasno razdvajanje između UI, logike prikaza i poslovne logike.
  • Otpornost na promene konfiguracije: ViewModel se čuva pri rotaciji ekrana i drugim promenama.
  • Poboljšana održivost koda.