Sobes.tech
Middle+

Como você implementaria sozinho uma abordagem arquitetônica MVVM?

sobes.tech IA

Resposta da IA

O MVVM (Model-View-ViewModel) é um padrão de arquitetura que separa a interface do utilizador, a lógica de apresentação e a lógica de negócio.

Componentes principais:

  • Model: Representa os dados e a lógica de negócio. Não depende da UI.
  • View: Camada de UI. Mostra os dados do ViewModel e envia ações do utilizador (eventos) ao ViewModel. Não contém lógica de negócio.
  • ViewModel: Contém a lógica de apresentação, prepara os dados do Model para exibição na View e processa as ações do utilizador. Não tem ligações diretas à View, interagindo através de fluxos observáveis (Streams observáveis).

Implementação autónoma:

  1. Criação do Model: Objetos POJO simples ou classes de dados Kotlin para representar dados, repositórios para aceder às fontes de dados (rede, base de dados).

    // Exemplo de Model
    data class User(val id: Int, val name: String, val email: String)
    
    class UserRepository {
        fun getUser(userId: Int): User {
            // Lógica para obter o utilizador da fonte de dados
            return User(userId, "Utilizador de teste $userId", "test$userId@example.com")
        }
    }
    
  2. Criação do ViewModel: Classe que herda de ViewModel dos Componentes de Arquitetura Android (ou uma implementação própria com consciência do ciclo de vida). Armazena LiveData ou Kotlin StateFlow/SharedFlow para dados observáveis. Contém métodos para lidar com ações do utilizador e atualizar dados.

    // Exemplo de ViewModel
    class UserViewModel(private val userRepository: UserRepository) : androidx.lifecycle.ViewModel() {
    
        private val _user = MutableLiveData<User>()
        val user: LiveData<User> = _user
    
        fun loadUser(userId: Int) {
            // Na aplicação real - carregamento assíncrono
            val loadedUser = userRepository.getUser(userId)
            _user.value = loadedUser // Atualização do LiveData
        }
    
        fun updateUser(newUser: User) {
            // Lógica de atualização do utilizador
            _user.value = newUser
        }
    }
    
  3. Implementação da View: Activity ou Fragment. Liga-se ao ViewModel, subscreve-se aos dados observáveis do ViewModel, atualiza a UI ao alterar os dados. Delegar o tratamento de eventos do utilizador (cliques, entrada de texto) ao ViewModel. Usa Data Binding ou View Binding para uma ligação mais declarativa.

    // Exemplo de 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)
    
            // Obtenção do ViewModel, preferencialmente via ViewModelProvider
            viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
    
            // Subscrever aos dados observáveis
            viewModel.user.observe(viewLifecycleOwner) { user ->
                // Atualizar a UI ao alterar o utilizador
                binding.userNameTextView.text = user.name
                binding.userEmailTextView.text = user.email
            }
    
            // Delegar evento ao ViewModel
            binding.loadUserButton.setOnClickListener {
                viewModel.loadUser(1) // Exemplo: carregar utilizador com ID 1
            }
        }
    
        override fun onDestroyView() {
            super.onDestroyView()
            _binding = null
        }
    }
    
  4. Ligação dos componentes: A View cria uma instância do ViewModel (através de ViewModelProvider) e subscreve-se aos seus dados observáveis. O ViewModel trabalha com o Model.

Aspectos-chave da implementação autónoma:

  • Uso de LiveData ou Flow para reatividade e atualização automática da UI ao alterar os dados.
  • Uso de ViewModelProvider para garantir o ciclo de vida correto do ViewModel.
  • Uso de Dependency Injection (por exemplo, Hilt ou Koin) para fornecer dependências (por exemplo, UserRepository) ao ViewModel.
  • Gestão de operações assíncronas (requisições de rede, trabalho com bases de dados) no ViewModel usando corutinas ou outros mecanismos.

Vantagens desta abordagem:

  • Testabilidade: O ViewModel pode ser facilmente testado de forma independente da UI.
  • Separação de responsabilidades: Clareza na separação entre UI, lógica de apresentação e lógica de negócio.
  • Resistência a mudanças de configuração: O ViewModel mantém-se durante rotações de ecrã e outras mudanças de configuração.
  • Melhor manutenção do código.