Visão geral do ViewModel (Views)

Conceitos e implementação do Jetpack Compose

A classe ViewModel é um detentor de estado da tela ou da lógica de negócios. Ele expõe o estado à interface e encapsula a lógica de negócios correspondente. A principal vantagem do ViewModel é que ele armazena o estado em cache e mantém essas informações mesmo após mudanças de configuração. Isso significa que a interface não precisa buscar dados novamente ao navegar entre diferentes atividades ou implementar mudanças de configuração, como ao girar a tela.

Benefícios do ViewModel

Uma alternativa para o uso de ViewModel é implementar uma classe simples contendo os dados mostrados na interface. Isso pode se tornar um problema ao navegar entre diferentes atividades ou destinos de navegação. Isso destrói esses dados se você não os armazenar usando o mecanismo de estado de instância salva. O ViewModel fornece uma API adequada para a persistência de dados que resolve esse problema.

Os principais benefícios da classe ViewModel são essencialmente dois:

  • Ele permite manter o estado da interface.
  • Oferece acesso à lógica de negócios.

Escopo

Ao instanciar um ViewModel, o sistema transmite um objeto que implementa a interface ViewModelStoreOwner. Esse objeto pode ser um destino ou um gráfico de navegação, uma atividade, um fragmento ou qualquer outro tipo que implemente a interface. Em seguida, o Lifecycle do ViewModelStoreOwner é definido como o escopo do ViewModel. Ele continua na memória até que o ViewModelStoreOwner apareça de forma definitiva.

Um intervalo de classes é uma subclasse direta ou indireta da interface ViewModelStoreOwner. As subclasses diretas são ComponentActivity, Fragment e NavBackStackEntry. Para uma lista completa de subclasses indiretas, consulte a documentação de referência do ViewModelStoreOwner.

Implementar um ViewModel

Confira abaixo um exemplo de implementação de um ViewModel para uma tela que permite que o usuário jogue o dado.

Kotlin

data class DiceUiState(
    val firstDieValue: Int? = null,
    val secondDieValue: Int? = null,
    val numberOfRolls: Int = 0,
)

class DiceRollViewModel : ViewModel() {

    // Expose screen UI state
    private val _uiState = MutableStateFlow(DiceUiState())
    val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()

    // Handle business logic
    fun rollDice() {
        _uiState.update { currentState ->
            currentState.copy(
                firstDieValue = Random.nextInt(from = 1, until = 7),
                secondDieValue = Random.nextInt(from = 1, until = 7),
                numberOfRolls = currentState.numberOfRolls + 1,
            )
        }
    }
}

Java

public class DiceUiState {
    private final Integer firstDieValue;
    private final Integer secondDieValue;
    private final int numberOfRolls;

    // ...
}

public class DiceRollViewModel extends ViewModel {

    private final MutableLiveData<DiceUiState> uiState =
        new MutableLiveData(new DiceUiState(null, null, 0));
    public LiveData<DiceUiState> getUiState() {
        return uiState;
    }

    public void rollDice() {
        Random random = new Random();
        uiState.setValue(
            new DiceUiState(
                random.nextInt(7) + 1,
                random.nextInt(7) + 1,
                uiState.getValue().getNumberOfRolls() + 1
            )
        );
    }
}

Depois, você pode acessar o ViewModel de uma atividade desta maneira:

Kotlin

import androidx.activity.viewModels

class DiceRollActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same DiceRollViewModel instance created by the first activity.

        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        val viewModel: DiceRollViewModel by viewModels()
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Update UI elements
                }
            }
        }
    }
}

Java

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.
        DiceRollViewModel model = new ViewModelProvider(this).get(DiceRollViewModel.class);
        model.getUiState().observe(this, uiState -> {
            // update UI
        });
    }
}