Livro 3 - Projeto Agenda de Contatos - Parte 2

4. Programando as transições

4.3. Classe AddEditFragment

A classe AddEditFragment fornece uma interface para adicionar novos contatos ou editar os já existentes.

4.3.1 Importação e Campos

O fragmento AddEditFragment possui variáveis para fazer a referência aos seus componentes gráficos pois o usuário deve digitar três campos: nome, telefone e e-mail. Além disso, a mesma interface é usada para adicionar e editar um contato existente por isso será usada uma tag para sinalizar quando o fragmento deve ler os dados de um contato já existente e iniciar sua edição ou apenas criar um contato novo. O fragmento usará a ViewModel para manipular os dados do contato já existente ou novo. Também, como no fragmento anterior é necessária a adição das importações das constantes para configuração da transição das telas precisamos.

import static br.com.bcalegaro.agendacontatos.MainActivity.CONTACT_ID;
import static br.com.bcalegaro.agendacontatos.MainActivity.NEW_CONTACT;

public class AddEditFragment extends Fragment {
private int contactID; // ID do contato selecionado
private boolean addingNewContact; // flag para sinalizar adição ou edição

// componente FAB para salvar o contato
private FloatingActionButton saveContactFAB;

// ViewModel do fragmento
private AddEditViewModel addEditViewModel;

4.3.2 Método onCreateView

No método onCreateView vamos inicializar os componentes da interface gráfica definidos no arquivo de layout add_edit_fragment. Futuramente vamos obter as referências aos componentes da interface gráfica. Mas para esta segunda parte do projeto vamos apenas vincular o tratamento de eventos do FAB.

@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 add_edit_fragment.xml
View view = inflater.inflate(R.layout.add_edit_fragment, container, false);

// TODO componentes TextInputLayout

// configura o receptor de eventos do FAB
saveContactFAB = view.findViewById(R.id.saveButton);
saveContactFAB.setOnClickListener(saveContactButtonClicked);
// acessa a lista de argumentos enviada ao fragmento em busca do ID do contato
Bundle arguments = getArguments();
contactID = arguments.getInt(CONTACT_ID);
// verifica se o fragmento deve criar um novo contato ou editar um já existente
if (contactID == NEW_CONTACT) {
// usa a flag para sinalizar que é um novo contato
addingNewContact = true;
} else {
// usa a flag para sinalizar que é uma edição
addingNewContact = false;
}
return view;
}

Ao se criar o fragmento, criamos um objeto arguments da classe Bundle para conseguirmos ler as informações repassadas pelo NavController na transição de telas. Buscamos o argumento com a chave CONTACT_ID e verificamos seu valor, assim conseguimos detectar se o fragmento foi invocado para uma operação de adição ou edição de um contato. A tag addingNewContact será usada na parte 3 do projeto, vamos programar para que em caso de edição os dados do contato existente sejam carregados do banco de dados e apresentados nos campos de edição. Caso contrário, por se tratar de um contato novo, a interface deve apresentar os campos de edição em branco.

4.3.3 Implementação de interface onClickListener com saveContactButtonClicked

O tratamento de eventos para o FAB do fragmento, botão flutuante salvar (saveButton), é cadastrado como a implementação da interface saveContactButtonClicked. O código executado acessa o sistema nativo do Android parar solicita para esconder o teclado virtual (hideSoftInputFromWindow). Por fim, é invodado o método saveContact para efetivamente salvar o novo contato.

private final View.OnClickListener saveContactButtonClicked = new View.OnClickListener() {
@Override
public void onClick(View view) {
// oculta o teclado virtual
((InputMethodManager) getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(
getView().getWindowToken(), 0);
saveContact();
}
};

4.3.4 Método saveContact

O método saveContact deve ler os dados preenchidos e salvar o contato criado/editado. Sua implementação completa se dará na parte 3 deste projeto. Por ora, vamos fazer apenas a configuração da transição de telas que neste caso é solicitar ao NavController voltar uma tela com o método popBackStack.

// salva informações de um contato no banco de dados
private void saveContact() {
// TODO ler dados inseridos
// TODO salvar dados
// solicita o retorno a tela anterior
Navigation.findNavController(getView()).popBackStack();
}

O BackStack é uma pilha, como o próprio nome diz, que armazena estados das telas em relação as transações. O BackStack permite, de forma transparente, a navegação entre os fragmentos ou atividades decorrente do empilhamento desses. O elemento no topo da pilha sempre será a tela atual, assim, remover o elemento do topo significa você voltar para a tela anterior, pop é ação de remover o estado no topo da pilha. Assim, não é necessário executar uma ação identificando origem e destino na navegação neste caso, apenas voltar uma tela é o suficiente.. 

4.3.5 Método onActivityCreated

O método de ciclo de vida onActivityCreated de Fragment é chamado depois que a atividade hospedeira de um fragmento foi criada e o método onCreateView terminou de executar. Usamos esse método para configurar a ViewModel. No entanto, nesta segunda parte do projeto apenas arrumar a nomenclatura do campo para conferir com addEditViewModel.

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
addEditViewModel = new ViewModelProvider(this).get(AddEditViewModel.class);
// TODO: Use the ViewModel
}