Livro 3 - Projeto Agenda de Contatos - Parte 3

4. ViewModel e vinculação de dados

4.3. DetailViewModel

Implementação da DetailViewModel

A DetailViewModel deve ser implementada para armazenar um contato específico e abstrair a solicitação ao repositório de apagar um contato já existente. Criamos o método getContactById para solicitar ao repositório um contato a partir de seu id e o método delete para o encaminhamento da operação ao repositório.

package ...

import android.app.Application;

import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;

import br.com.bcalegaro.agendacontatos.data.Contact;
import br.com.bcalegaro.agendacontatos.data.ContactsRepository;

public class DetailViewModel extends AndroidViewModel {
private LiveData<Contact> mContact;
private ContactsRepository mRepository;

public DetailViewModel (Application application) {
super(application);
mRepository = new ContactsRepository(application);
}

public LiveData<Contact> getContactById(int id) {
mContact = mRepository.getContactById(id);
return mContact;
}

public void delete() { mRepository.delete(mContact.getValue()); }
}

Vinculação dos dados na DetailFragment

Para fazer a vinculação dos dados da ViewModel ao fragmento vamos modificar o método onActivityCreated de DetailFragment. Nesse fragmento devemos, ou criar um novo contato e assim apresentar dados em branco nas caixas de texto, ou buscar as informações de um contato específico e apresentá-las na tela. Fazemos isso através da solicitação a ViewModel com o método getContactById e configurando que ao ser retornado os dados as informações na tela sejam atualizadas.

Primeiramente, adicione os seguintes campos na classe:

// componentes TextView para informações de contato
private TextView nameTextView;
private TextView phoneTextView;
private TextView emailTextView;

Configure a inicialização dos campos:

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
// cria o fragmento com o layout do arquivo details_fragment.xml
View view = inflater.inflate(R.layout.detail_fragment, container, false);
// configura o fragmento para exibir itens de menu
setHasOptionsMenu(true);
// obtem as referências dos componentes
nameTextView = (TextView) view.findViewById(R.id.nameTextView);
phoneTextView = (TextView) view.findViewById(R.id.phoneTextView);
emailTextView = (TextView) view.findViewById(R.id.emailTextView);
// acessa a lista de argumentos enviada ao fragmento em busca do ID do contato
Bundle arguments = getArguments();
if (arguments != null)
contactID = arguments.getInt(CONTACT_ID);
return view;
}

Por fim, configure a ViewModel para buscar as informações de um contato e atualizar os dados na tela.

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
detailViewModel = new ViewModelProvider(this).get(DetailViewModel.class);
detailViewModel.getContactById(contactID).observe(getViewLifecycleOwner(), new Observer<Contact>() {
@Override
public void onChanged(@Nullable final Contact contact) {
// atualiza as informações da tela com os dados do contato lido
nameTextView.setText(contact.getName());
phoneTextView.setText(contact.getPhone());
emailTextView.setText(contact.getEmail());
}
});
}

Por fim, modifique o método deleteContact para fazer o uso da ViewModel:

// exclui um contato
private void deleteContact() {
// usa a ViewModel para apagar o contato aberto
detailViewModel.delete();
Navigation.findNavController(getView()).popBackStack();
}