Trata-se de um padrão de projeto arquitetural, as camadas são divididas em Model, View e View-Model.

Model: Responsável pela manipulação dos dados. Nesta parte compreendem as classes que representam as entidades e que realizam as persistências no banco de dados.

View: Parte visual do projeto. A View relaciona-se com o ViewModel e não conhece diretamente o Model.

ViewModel: Camada intermediária entre a View e o Model. O ViewModel pode ter acesso ao Model diretamente. O ViewModel atualiza o objeto LiveData através da atualização do Model. O LiveData usa o método observe para atualizar a View.

Para mais detalhes sobre MVVM acesse o material: SOUTO, Thiago. Arquiteturas em Android: MVVM + Kotlin + Android Architecture Components (Databinding, Lifecycle, LiveData, Room). 2019. Disponível em: https://medium.com/android-dev-br/arquiteturas-em-android-mvvm-kotlin-android-architecture-components-databinding-lifecycle-d5e7a9023cf3.Acessao em 25 ago. 2025.

Responsabilidades de alguns componentes dentro do MVVM:

  • DataBinding: permite o vínculo da View (por exemplo, um TextView) com um ViewModel. O vínculo é feito de forma declarativa no XML.

  • LiveData: é um tipo que pode ser observado. Isso significa que os componentes da UI (como Activities e Fragments) podem se inscrever para receber atualizações sobre mudanças nos dados. Notifica apenas os observadores que estão em um estado ativo.

O MVVM garante que a interface do usuário seja sempre atualizada de acordo com o ciclo de vida do componente.

Exemplo prático 01 (com DataBinding e ViewModel):

Inicialmente no projeto criado habilite o DataBinding, no arquivo gradle a nível de app, acrescente as seguintes linhas:

android{ ...
   buildFeatures {
        dataBinding = true
    }
}
  • activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
        <data>
            <variable
                name="viewModel"
                type="nomeDoPacote.CalculadoraViewModel" />
        </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:padding="16dp">
            <EditText
                android:id="@+id/editTextN1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Número 1"
                android:inputType="numberDecimal" />
            <EditText
                android:id="@+id/editTextN2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Número 2"
                android:inputType="numberDecimal" />
            <EditText
                android:id="@+id/editTextOperador"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Operador (+, -, *, /)"
                android:inputType="text" />
            <Button
                android:id="@+id/buttonCalcular"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Calcular" />
            <TextView
                android:id="@+id/textViewResultado"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{viewModel.resultado}" />
        </LinearLayout>
    </layout>
  • Calculadora.java

    public class Calculadora {
        public double calcular(double value1, double value2, String operator) {
            switch (operator) {
                case "+":
                    return value1 + value2;
                case "-":
                    return value1 - value2;
                case "*":
                    return value1 * value2;
                case "/":
                    return value1 / value2;
                default:
                    return 0;
            }
        }
    }
  • CalculadoraViewModel.java

    import androidx.lifecycle.LiveData;
    import androidx.lifecycle.MutableLiveData;
    import androidx.lifecycle.ViewModel;
    public class CalculadoraViewModel extends ViewModel {
        private final Calculadora calculadora;
        private final MutableLiveData<String> resultado;
        public CalculadoraViewModel(){
            calculadora = new Calculadora();
            resultado = new MutableLiveData<>();
        }
        public LiveData<String> getResultado() {
            return resultado;
        }
        public void calcular(double n1, double n2, String op) {
                double calculationResult = calculadora.calcular(n1, n2, op);
                resultado.setValue(String.valueOf(calculationResult));
        }
    }
  • MainActivity.java

    import android.os.Bundle;
    import android.view.View;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.lifecycle.ViewModelProvider;
    import androidx.databinding.DataBindingUtil;
    import nomeDoPacote.ActivityMainBinding;
    public class MainActivity extends AppCompatActivity {
        private CalculadoraViewModel viewModel;
        private ActivityMainBinding binding;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            viewModel = new ViewModelProvider(this).get(CalculadoraViewModel.class);
            binding.setViewModel(viewModel);
            binding.setLifecycleOwner(this);
            binding.buttonCalcular.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    double n1 = Double.parseDouble(binding.editTextN1.getText().toString());
                    double n2 = Double.parseDouble(binding.editTextN2.getText().toString());
                    String op = binding.editTextOperador.getText().toString().trim();
                    viewModel.calcular(n1, n2, op);
                }
            });
        }
    }

Exemplo prático 02 (sem DataBinding e com ViewModel):

  • activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp">
        <EditText
            android:id="@+id/editTextN1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Número 1"
            android:inputType="numberDecimal"
            android:padding="8dp"
            android:textSize="16sp" />
        <EditText
            android:id="@+id/editTextN2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Número 2"
            android:inputType="numberDecimal"
            android:padding="8dp"
            android:textSize="16sp" />
        <EditText
            android:id="@+id/editTextOp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Operador (+, -, *, /)"
            android:inputType="text"
            android:padding="8dp"
            android:textSize="16sp" />
        <Button
            android:id="@+id/buttonCalculadora"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Calcular"
            android:layout_marginTop="12dp"
            android:padding="8dp"
            android:textSize="16sp" />
        <TextView
            android:id="@+id/textViewResultado"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Resultado: "
            android:textSize="18sp"
            android:paddingTop="16dp"
            android:textStyle="bold" />
    </LinearLayout>
  • Calculadora.java

    public class Calculadora {
        public double calcular(double n1, double n2, String op) {
            switch (op) {
                case "+":
                    return n1 + n2;
                case "-":
                    return n1 - n2;
                case "*":
                    return n1 * n2;
                case "/":
                        return n1 / n2;
                default:
                   return 0;
            }
        }
    }
  • CalculadoraViewModel.java

    import androidx.lifecycle.LiveData;
    import androidx.lifecycle.MutableLiveData;
    import androidx.lifecycle.ViewModel;
    public class CalculadoraViewModel extends ViewModel {
        private final Calculadora modelo = new Calculadora();
        private final MutableLiveData<String> resultado = new MutableLiveData<>();
        public LiveData<String> getResultado() {
            return resultado;
        }
        public void calculate(double n1, double n2, String op) {
                double calculationResult = modelo.calcular(n1, n2, op);
                resultado.setValue("Resultado: " + calculationResult);
        }
    }
  • MainActivity.java

    import android.os.Bundle;
    import android.text.TextUtils;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.TextView;
    import androidx.appcopat.app.AppCompatActivity;
    import androidx.lifecycle.Observer;
    import androidx.lifecycle.ViewModelProvider;
    public class MainActivity extends AppCompatActivity {
        private CalculadoraViewModel viewModel;
        private TextView textViewResultado;
        private EditText editTextN1, editTextN2, editTextOp;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textViewResultado = findViewById(R.id.textViewResultado);
            Button buttonCalculadora = findViewById(R.id.buttonCalculadora);
            editTextN1 = findViewById(R.id.editTextN1);
            editTextN2 = findViewById(R.id.editTextN2);
            editTextOp = findViewById(R.id.editTextOp);
            viewModel = new ViewModelProvider(this).get(CalculadoraViewModel.class);
            viewModel.getResultado().observe(this, new Observer<String>() {
                @Override
                public void onChanged(String result) {
                    textViewResultado.setText(result);
                }
            });
            buttonCalculadora.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String s1 = editTextN1.getText().toString().trim();
                    String s2 = editTextN2.getText().toString().trim();
                    String op = editTextOp.getText().toString().trim();
                    double n1 = Double.parseDouble(s1);
                    double n2 = Double.parseDouble(s2);
                    viewModel.calculate(n1, n2, op);
                }
            });
        }
    }

Exemplo prático 03:

  • Aluno.java (Model)

    public class Aluno {
        private String nome;
        private int nota;
        public Aluno(String nome, int nota) {
            this.nome = nome;
            this.nota = nota;
        }
        public String getNome() {
            return nome;
        }
        public void setNome(String nome) {
            this.nome = nome;
        }
        public int getNota() {
            return nota;
        }
        public void setNota(int nota) {
            this.nota = nota;
        }
        @Override
        public String toString() {
            return "Aluno{" +
                    "nome='" + nome + '\'' +
                    ", nota=" + nota +
                    '}';
        }
    }
  • AlunoRepositorio.java (Model)

    import java.util.ArrayList;
    import java.util.List;
    public class AlunoRepositorio {
        public List<Aluno> obterDadosAlunos() {
            List<Aluno> listaAlunos = new ArrayList<>();
            listaAlunos.add(new Aluno("Ana", 6));
            listaAlunos.add(new Aluno("Rodrigo", 8));
            listaAlunos.add(new Aluno("Paulo", 7));
            return listaAlunos;
        }
    }
  • AlunoAdapter.java (Controller)

    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.TextView;
    import java.util.List;
    public class AlunoAdapter extends ArrayAdapter<Aluno> {
        public AlunoAdapter(Context context, List<Aluno> alunos) {
            super(context, 0, alunos);
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Aluno aluno = getItem(position);
            if (convertView == null) {
                convertView = LayoutInflater.from(getContext())
                        .inflate(R.layout.item_aluno, parent, false);
            }
            TextView textViewNome = convertView.findViewById(R.id.textViewNome);
            TextView textViewNota = convertView.findViewById(R.id.textViewNota);
            if (aluno != null) {
                textViewNome.setText(aluno.getNome());
                textViewNota.setText("Nota: " + aluno.getNota());
            }
            return convertView;
        }
    }
  • AlunoViewModel.java (Controller)

    import androidx.lifecycle.LiveData;
    import androidx.lifecycle.MutableLiveData;
    import androidx.lifecycle.ViewModel;
    import java.util.List;
    public class AlunoViewModel extends ViewModel {
        private final MutableLiveData<List<Aluno>> alunos;
        private final AlunoRepositorio alunoRepositorio;
        public AlunoViewModel() {
            alunos = new MutableLiveData<>();
            alunoRepositorio = new AlunoRepositorio();
            alunos.setValue(alunoRepositorio.obterDadosAlunos());
        }
        public LiveData<List<Aluno>> getAlunos() {
            return alunos;
        }
    }
  • activity_main.xml (View)

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp">
        <ListView
            android:id="@+id/listViewAlunos"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
  • item_aluno.xml (View)

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="12dp">
        <TextView
            android:id="@+id/textViewNome"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Nome"
            android:textSize="18sp"
            android:textStyle="bold" />
        <TextView
            android:id="@+id/textViewNota"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Nota"
            android:textSize="16sp" />
    </LinearLayout>
  • MainActivity.java (View)

    import android.os.Bundle;
    import android.widget.ListView;
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.lifecycle.Observer;
    import androidx.lifecycle.ViewModelProvider;
    import java.util.ArrayList;
    import java.util.List;
    public class MainActivity extends AppCompatActivity {
        private AlunoViewModel alunoViewModel;
        private ListView listViewAlunos;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listViewAlunos = findViewById(R.id.listViewAlunos);
            alunoViewModel = new ViewModelProvider(this).get(AlunoViewModel.class);
            final AlunoAdapter adapter = new AlunoAdapter(this, new ArrayList<Aluno>());
            listViewAlunos.setAdapter(adapter);
            alunoViewModel.getAlunos().observe(this, new Observer<List<Aluno>>() {
                @Override
                public void onChanged(List<Aluno> alunos) {
                    adapter.clear();
                    adapter.addAll(alunos);
                    adapter.notifyDataSetChanged();
                }
            });
        }
    }

Exemplo prático 04:

  • Bolo.java

    public class Bolo {
        private String nome;
        private String receita;
        public Bolo(String nome, String receita) {
            this.nome = nome;
            this.receita = receita;
        }
        public String getNome() {
            return nome;
        }
        public String getReceita() {
            return receita;
        }
    }
  • BoloRepositorio.java

    import java.util.ArrayList;
    import java.util.List;
    public class BoloRepositorio {
        public List<Bolo> getBolos() {
            List<Bolo> bolos = new ArrayList<>();
            bolos.add(new Bolo("Bolo de Fubá", "Receita: Fubá, leite, ovos..."));
            bolos.add(new Bolo("Bolo de Chocolate", "Receita: Chocolate, leite, ovos..."));
            bolos.add(new Bolo("Bolo de Mandioca", "Receita: Mandioca, leite, ovos..."));
            return bolos;
        }
    }
  • BoloViewModel.java

    import androidx.lifecycle.LiveData;
    import androidx.lifecycle.MutableLiveData;
    import androidx.lifecycle.ViewModel;
    import java.util.List;
    public class BoloViewModel extends ViewModel {
        private final BoloRepositorio repository = new BoloRepositorio();
        private final MutableLiveData<List<Bolo>> bolos = new MutableLiveData<>();
        public BoloViewModel() {
            loadBolos();
        }
        private void loadBolos() {
            bolos.setValue(repository.getBolos());
        }
        public LiveData<List<Bolo>> getBolos() {
            return bolos;
        }
    }
  • BoloAdapter.java

    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.TextView;
    import java.util.List;
    public class BoloAdapter extends ArrayAdapter<Bolo> {
        public BoloAdapter(Context context, List<Bolo> bolos) {
            super(context, 0, bolos);
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Bolo bolo = getItem(position);
            if (convertView == null) {
                convertView = LayoutInflater.from(getContext())
                        .inflate(R.layout.item_bolo, parent, false);
            }
            TextView textViewNome = convertView.findViewById(R.id.textViewNome);
            if (bolo != null) {
                textViewNome.setText(bolo.getNome());
            }
            return convertView;
        }
    }
  • ReceitaFragment.java

    import android.os.Bundle;
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    public class ReceitaFragment extends Fragment {
        private static final String ARG_RECEITA = "receita";
        public static ReceitaFragment newInstance(String receita) {
            ReceitaFragment fragment = new ReceitaFragment();
            Bundle args = new Bundle();
            args.putString(ARG_RECEITA, receita);
            fragment.setArguments(args);
            return fragment;
        }
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater,
                                 @Nullable ViewGroup container,
                                 @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_receita, container, false);
            TextView textViewReceita = view.findViewById(R.id.textViewReceita);
            if (getArguments() != null) {
                String receita = getArguments().getString(ARG_RECEITA);
                textViewReceita.setText(receita);
            }
            return view;
        }
    }
  • item_bolo.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">
        <TextView
            android:id="@+id/textViewNome"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Nome do bolo"
            android:textSize="18sp" />
    </LinearLayout>
  • fragment_receita.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp">
        <TextView
            android:id="@+id/textViewReceita"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Receita"
            android:textSize="18sp" />
    </LinearLayout>
  • activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ListView
            android:id="@+id/listViewBolos"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true" />
        <FrameLayout
            android:id="@+id/fragment_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/listViewBolos" />
    </RelativeLayout>
  • MainActivity.java

    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ListView;
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.lifecycle.Observer;
    import androidx.lifecycle.ViewModelProvider;
    import java.util.ArrayList;
    import java.util.List;
    public class MainActivity extends AppCompatActivity {
        private BoloViewModel boloViewModel;
        private ListView listViewBolos;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listViewBolos = findViewById(R.id.listViewBolos);
            boloViewModel = new ViewModelProvider(this).get(BoloViewModel.class);
            final BoloAdapter adapter = new BoloAdapter(this, new ArrayList<Bolo>());
            listViewBolos.setAdapter(adapter);
            boloViewModel.getBolos().observe(this, new Observer<List<Bolo>>() {
                @Override
                public void onChanged(List<Bolo> bolos) {
                    adapter.clear();
                    adapter.addAll(bolos);
                    adapter.notifyDataSetChanged();
                }
            });
            listViewBolos.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Bolo bolo = adapter.getItem(position);
                    if (bolo != null) {
                        ReceitaFragment fragment = ReceitaFragment.newInstance(bolo.getReceita());
                        getSupportFragmentManager().beginTransaction()
                                .replace(R.id.fragment_container, fragment)
                                .addToBackStack(null)
                                .commit();
                    }
                }
            });
        }
    }