No tutorial anterior, você modificou o aplicativo AndroidTrivia para adicionar navegação ao aplicativo. Neste tutorial, você modifica o aplicativo para que o usuário possa compartilhar os resultados do jogo. O usuário pode iniciar um e-mail ou texto, ou pode copiar os resultados do jogo para a área de transferência.

O que você já deveria saber

O que aprenderá

O que fará

O aplicativo AndroidTrivia, no qual você trabalhou nos dois tutoriais anteriores, é um jogo no qual os usuários respondem a perguntas sobre o desenvolvimento do Android. Se o usuário responder a três perguntas corretamente, ele ganha o jogo.

Se você concluiu o tutorial anterior, use esse código como o código inicial para este tutorial. Caso contrário, baixe o arquivo AndroidTriviaNavigation para obter o código inicial.

Neste tutorial, você atualiza o aplicativo AndroidTrivia para que os usuários possam enviar seus resultados de jogos para outros aplicativos e compartilhar seus resultados com amigos.

Antes que os usuários possam compartilhar seus resultados de jogos de dentro do aplicativo AndroidTrivia, seu código precisa passar parâmetros de um fragmento para outro. Para evitar erros nessas transações e torná-las seguras quanto ao tipo, use um plug-in Gradle chamado Safe Args. O plug-in gera classes NavDirection e você adiciona essas classes ao seu código.

Em tarefas posteriores neste tutorial, você usa as classes NavDirection geradas para passar argumentos entre fragmentos.

Por que você precisa do plugin Safe Args

Frequentemente, seu aplicativo precisará passar dados entre fragmentos. Uma maneira de passar dados de um fragmento para outro é usar uma instância da classe Bundle. Um Android Bundle é um armazenamento de valor-chave.

Um armazenamento de valor-chave, também conhecido como dicionário ou array associativo, é uma estrutura de dados onde você usa uma chave única (uma string) para buscar o valor associado a essa chave. Por exemplo:

Chave

Valor

"name"

"Anika"

"favorite_weather"

"sunny"

"favorite_color"

"blue"

Seu aplicativo pode usar um Bundle para passar dados do fragmento A para o fragmento B. Por exemplo, o fragmento A cria um pacote e salva as informações como pares de chave-valor e, em seguida, passa o Bundle para o fragmento B. Em seguida, o fragmento B usa uma chave para buscar um par de valor-chave do Bundle. Essa técnica funciona, mas pode resultar em código que compila, mas pode causar erros durante a execução do aplicativo.

Os tipos de erros que podem ocorrer são:

Você deseja detectar esses erros ao compilar o aplicativo no Android Studio, de modo que possa detectar esses erros antes de implantar o aplicativo na produção. Em outras palavras, você deseja detectar os erros durante o desenvolvimento do aplicativo para que os usuários não os encontrem.

Para ajudar com esses problemas, o componente de arquitetura de navegação do Android inclui um recurso chamado Safe Args. Safe Args é um plug-in do Gradle que gera código e classes que ajudam a detectar erros em tempo de compilação que podem não aparecer de outra forma até que o aplicativo seja executado.

Etapa 1: Abra o aplicativo inicial e execute-o

  1. Obtenha o aplicativo AndroidTrivia inicial para este tutorial:

Execute o aplicativo no Android Studio:

  1. Abra o aplicativo no Android Studio.
  2. Execute o aplicativo em um dispositivo Android ou em um emulador. O aplicativo é um jogo de perguntas e respostas com uma gaveta de navegação, um menu de opções na tela principal e um botão Acima na parte superior da maioria das telas.
  3. Explore o aplicativo e jogue. Quando você ganha o jogo respondendo três perguntas corretamente, você vê a tela de Congratulations.

    Neste tutorial, você adiciona um ícone de share para parte superior da tela de Congratulations. O ícone share permite que o usuário compartilhe seus resultados em um e-mail ou texto.

Etapa 2: Adicione Safe Args ao projeto

  1. No Android Studio, abra o arquivo build.gradle de nível de projeto.
  2. Adicione a dependência navigation-safe-args-gradle-plugin, conforme mostrado abaixo:
dependencies {
   ...
classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"

}
  1. Abra o arquivo build.gradle de nível de aplicativo.
  2. Na parte superior do arquivo, após todos os outros plug-ins, adicione a instrução apply plugin com o plug-in androidx.navigation.safeargs:
apply plugin: 'androidx.navigation.safeargs'
  1. Reconstrua o projeto. Se você for solicitado a instalar ferramentas de compilação adicionais, instale-as.

O projeto do aplicativo agora inclui classes NavDirection geradas.

O plugin Safe Args gera uma classe NavDirection para cada fragmento. As classes representam a navegação de todas as ações do aplicativo.

Por exemplo, GameFragment agora tem uma classe gerada GameFragmentDirections. Você pode usar a classe GameFragmentDirections para passar argumentos de tipo seguro entre o fragmento do jogo e outros fragmentos no aplicativo.

Para ver os arquivos gerados, explore a pasta generatedJava no painel Project > Android.

Etapa 3: Adicione uma classe NavDirection ao fragmento do jogo

Nesta etapa, você adiciona a classe GameFragmentDirections ao fragmento do jogo. Você usará este código posteriormente para passar argumentos entre o GameFragment e os fragmentos de estado do jogo (GameWonFragment e GameOverFragment).

  1. Abra o arquivo GameFragment.kt Kotlin que está na pasta java.
  2. Dentro do método onCreateView(), localize a declaração condicional de jogo vencido ("Ganhamos!"). Altere o parâmetro que é passado para o método NavController.navigate(): Substitua o ID da ação para o estado de ganho do jogo por um ID que usa o actionGameFragmentToGameWonFragment() método da classe GameFragmentDirections.

    A instrução condicional agora se parece com o código a seguir. Você adicionará parâmetros ao método actionGameFragmentToGameWonFragment() na próxima tarefa.
view.findNavController()
        .navigate(GameFragmentDirections.actionGameFragmentToGameWonFragment())
  1. Da mesma forma, localize a declaração condicional game-over ("Game over!"). Substitua o ID da ação para o estado de final de jogo por um ID que use o método de final de jogo da classe GameFragmentDirections:
view.findNavController()
        .navigate(GameFragmentDirections.actionGameFragmentToGameOverFragment())

Nesta tarefa, você adiciona argumentos a gameWonFragment e passa os argumentos para um método GameFragmentDirections. Em seguida, você substitui as outras classes de fragmento por suas classes NavDirection equivalentes.

Etapa 1: Adicione argumentos ao fragmento ganho pelo jogo

  1. Abra o arquivo navigation.xml, que está na pasta res > navigation. Clique na guia Design para abrir o grafo de navegação, que é onde você definirá os argumentos nos fragmentos.
  2. Na prévia, selecione gameWonFragment.
  3. No painel Attributes, expanda a seção Arguments.
  4. Clique no ícone + para adicionar um argumento. Nomeie o argumento como numQuestions e defina o tipo como Integer e clique em Add. Este argumento representa o número de perguntas que o usuário respondeu.

  5. Ainda com o gameWonFragment selecionado, adicione um segundo argumento. Nomeie este argumento como numCorrect e defina seu tipo como Integer. Este argumento representa o número de perguntas que o usuário respondeu corretamente.

Se você tentar construir o aplicativo agora, provavelmente obterá dois erros de compilação.

No value passed for parameter 'numQuestions'
No value passed for parameter 'numCorrect'

Você corrige esse erro nas próximas etapas.

Etapa 2: Passe os argumentos

Nesta etapa, você passa os argumentos numQuestions e questionIndex para o método actionGameFragmentToGameWonFragment() da classe GameFragmentDirections.

  1. Abra o arquivo GameFragment.kt Kotlin e localize a declaração condicional de jogo vencido:
else {
 view.findNavController()
      .navigate(GameFragmentDirections
            .actionGameFragmentToGameWonFragment())
}
  1. Passe os parâmetros numQuestions e questionIndex para o método actionGameFragmentToGameWonFragment():
view.findNavController()
      .navigate(GameFragmentDirections
            .actionGameFragmentToGameWonFragment(numQuestions, questionIndex))

Você passa o número total de questões como numQuestions e a questão atual tentada como questionIndex. O aplicativo é projetado de forma que o usuário somente possa compartilhar seus dados se responder a todas as perguntas corretamente - o número de perguntas corretas é sempre igual ao número de perguntas respondidas. (Você pode alterar essa lógica de jogo mais tarde, se quiser).

  1. Em GameWonFragment.kt, extraia os argumentos do pacote e use um Toast para exibir os argumentos. Coloque o seguinte código no método onCreateView(), antes da instrução return:
val args = GameWonFragmentArgs.fromBundle(arguments!!)
Toast.makeText(context, "NumCorrect: ${args.numCorrect}, NumQuestions: ${args.numQuestions}", Toast.LENGTH_LONG).show()
  1. Execute o aplicativo e jogue o jogo para certificar-se de que os argumentos sejam passados ​​com sucesso para o GameWonFragment. A mensagem do sistema aparece na tela Congratulations, dizendo "NumCorrect: 3, NumQuestions: 3".

    Você precisa vencer o jogo de perguntas e respostas primeiro. Para tornar o jogo mais fácil, você pode alterá-lo para um jogo de pergunta única definindo o valor de numQuestions para 1 no GameFragment.kt Arquivo Kotlin.

Etapa 3: Substitua classes de fragmento por classes NavDirection

Ao usar "argumentos seguros", você pode substituir as classes de fragmento que são usadas no código de navegação por classes NavDirection. Faça isso para poder usar argumentos de tipo seguro com outros fragmentos no aplicativo.

Em TitleFragment, GameOverFragment e GameWonFragment, altere o ID da ação que é passado para o método navigate(). Substitua o ID da ação pelo método equivalente da classe NavDirection apropriada:

  1. Abra o arquivo TitleFragment.kt Kotlin. Em onCreateView(), localize o método navigate() no tratador de cliques do botão Play. Passe TitleFragmentDirections.actionTitleFragmentToGameFragment() como o argumento do método:
binding.playButton.setOnClickListener { view: View ->
    view.findNavController()
            .navigate(TitleFragmentDirections.actionTitleFragmentToGameFragment())
}
  1. No arquivo GameOverFragment.kt, no tratador de cliques do botão Try Again, passe GameOverFragmentDirections.actionGameOverFragmentToGameFragment() como navigate() argumento do método:
binding.tryAgainButton.setOnClickListener { view: View ->
    view.findNavController()
            .navigate(GameOverFragmentDirections.actionGameOverFragmentToGameFragment())
}
  1. No arquivo GameWonFragment.kt, no tratador de cliques do botão Next Match, passe GameWonFragmentDirections.actionGameWonFragmentToGameFragment() como navigate() argumento do método:
binding.nextMatchButton.setOnClickListener { view: View ->
    view.findNavController()
            .navigate(GameWonFragmentDirections.actionGameWonFragmentToGameFragment())
}
  1. Execute o aplicativo.

    Você não encontrará nenhuma alteração na saída do aplicativo, mas agora o aplicativo está configurado para que você possa facilmente passar argumentos usando as classes NavDirection sempre que necessário.

Nesta tarefa, você usa uma intenção implícita para adicionar um recurso de compartilhamento ao aplicativo para que o usuário possa compartilhar os resultados do jogo. Você implementa o recurso de compartilhamento como um menu de opções dentro da classe GameWonFragment. Na IU do aplicativo, o item de menu aparecerá como um ícone share na parte superior da tela Congratulations.

Intenções implícitas

Até agora, você usou componentes de navegação para navegar entre fragmentos dentro de sua atividade. O Android também permite que você use intents para navegar para atividades que outros aplicativos fornecem. Você usa essa funcionalidade no aplicativo AndroidTrivia para permitir que o usuário compartilhe os resultados do jogo.

Um Intent é um objeto de mensagem simples usado para se comunicar entre os componentes do Android. Com uma intenção implícita, você inicia uma atividade sem saber qual aplicativo ou atividade executará a tarefa. Por exemplo, se você quiser que seu aplicativo tire uma foto, normalmente não se importa com qual aplicativo ou atividade realiza a tarefa. Quando vários aplicativos Android podem tratar com a mesma intenção implícita, o Android mostra ao usuário um seletor, para que o usuário possa selecionar um aplicativo para tratar com a solicitação.

Cada intenção implícita deve ter uma ACTION que descreve o tipo de ação que deve ser feito. Ações comuns, como ACTION_VIEW, ACTION_EDIT e ACTION_DIAL, são definidas na classe Intent.

Para obter mais informações sobre intenções implícitas, consulte Enviando o usuário para outro aplicativo.

Etapa 1: Adicione um menu de opções à tela de Parabéns

  1. Abra o arquivo GameWonFragment.kt Kotlin.
  2. Dentro do método onCreateView(), antes do return, chame o método setHasOptionsMenu() e passe true:
  setHasOptionsMenu(true)

Etapa 2: Construa e chamar uma intenção implícita

Modifique seu código para construir e chamar um Intent que envia a mensagem sobre os dados do jogo do usuário. Como vários aplicativos diferentes podem tratar com uma intenção ACTION_SEND, o usuário verá um seletor que permite selecionar como deseja enviar suas informações.

  1. Dentro da classe GameWonFragment, após o método onCreateView(), crie um método privado chamado getShareIntent(), conforme mostrado abaixo. A linha de código que define um valor para args é idêntica à linha de código usada em onCreateView() da classe.

    No resto do código do método, você constrói uma ACTION_SEND intenção de entregar a mensagem que o usuário deseja compartilhar. O tipo MIME dos dados é especificado pelo método setType(). Os dados reais a serem entregues são especificados em EXTRA_TEXT. (A string share_success_text é definida no arquivo de recurso strings.xml).
private fun getShareIntent() : Intent {
   val args = GameWonFragmentArgs.fromBundle(arguments!!)
   val shareIntent = Intent(Intent.ACTION_SEND)
        shareIntent.setType("text/plain")
            .putExtra(Intent.EXTRA_TEXT, getString(R.string.share_success_text, args.numCorrect, args.numQuestions))
   return shareIntent
}
  1. Abaixo do método getShareIntent(), crie um método shareSuccess(). Este método obtém o Intent de getShareIntent() e chama startActivity() para iniciar o compartilhamento.
private fun shareSuccess() {
   startActivity(getShareIntent())
}
  1. O código inicial já contém um arquivo de menu winner_menu.xml. Substitua onCreateOptionsMenu() para inflar o winner_menu.

    Use getShareIntent() para obter o shareIntent. Para certificar-se de que o shareIntent é resolvido para uma Activity, verifique com o gerenciador de pacotes Android (PackageManager), que mantém rastrear os aplicativos e atividades instalados no dispositivo. Use a propriedade packageManager da atividade para obter acesso ao gerenciador de pacotes e chame resolveActivity(). Se o resultado for igual a null, o que significa que shareIntent não resolve, encontre o item de menu de compartilhamento no menu inflado e torne o item de menu invisível.
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
   super.onCreateOptionsMenu(menu, inflater)
   inflater?.inflate(R.menu.winner_menu, menu)
   if (null == getShareIntent().resolveActivity(activity!!.packageManager)) {
       menu?.findItem(R.id.share)?.setVisible(false)
   }
}
  1. Para manipular o item de menu, substitua onOptionsItemSelected(). Chame o método shareSuccess() quando o item de menu for clicado:
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
   when (item!!.itemId) {
       R.id.share -> shareSuccess()
   }
   return super.onOptionsItemSelected(item)
}
  1. Agora execute seu aplicativo. (Você pode precisar importar alguns pacotes para GameWonFragment.kt antes que o código seja executado). Depois de ganhar o jogo, observe o ícone share que aparece no canto superior direito de a barra de aplicativos. Clique no ícone de compartilhamento para compartilhar uma mensagem sobre sua vitória.

Projeto Android Studio: AndroidTrivia-Solution

Safe Args:

Intenções implícitas:

Funcionalidade de compartilhamento:

Quando o usuário toca no item de menu, a intenção é disparada e o usuário vê um seletor para a ação SEND.

Documentação para desenvolvimento em Android:

Esta seção lista as possíveis tarefas de casa para os alunos que estão trabalhando neste tutorial como parte de um curso ministrado por um instrutor.

Responda estas perguntas

Pergunta 1

Se você passar argumentos do Fragmento A para o Fragmento B sem usar Safe Args para garantir que seus argumentos sejam seguros para o tipo, qual dos problemas a seguir pode ocorrer e fazer com que o aplicativo trave durante a execução? Selecione tudo que se aplica.

Pergunta 2

O que o plug-in Safe Args Gradle faz? Selecione tudo que se aplica:

Pergunta 3

O que é uma intenção implícita?

Comece a próxima lição: 04.1: Ciclos de vida e registro

Para obter enlaces para outros tutoriais neste curso, consulte a página de destino dos tutoriais Fundamentos de Android em Kotlin.