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.
Bundle
para passar argumentos de um fragmento para outroNavDirection
.
NavDirection
para passar argumentos de tipo seguro entre o
GameFragment
e os fragmentos de estado do jogo.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.
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:
null
. Novamente, isso não gera um erro quando o aplicativo é
compilado, mas pode causar problemas graves quando o usuário executa o aplicativo.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.
Execute o aplicativo no Android Studio:
build.gradle
de nível de projeto.navigation-safe-args-gradle-plugin
, conforme mostrado abaixo:dependencies {
...
classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
}
build.gradle
de nível de aplicativo.apply plugin
com o plug-in androidx.navigation.safeargs
:apply plugin: 'androidx.navigation.safeargs'
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.
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
).
GameFragment.kt
Kotlin que está na pasta java. 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
.actionGameFragmentToGameWonFragment()
na próxima tarefa.
view.findNavController()
.navigate(GameFragmentDirections.actionGameFragmentToGameWonFragment())
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.
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.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.
Nesta etapa, você passa os argumentos numQuestions
e questionIndex
para o método
actionGameFragmentToGameWonFragment()
da classe GameFragmentDirections
.
GameFragment.kt
Kotlin e localize a declaração condicional de jogo vencido:else {
view.findNavController()
.navigate(GameFragmentDirections
.actionGameFragmentToGameWonFragment())
}
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).
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()
GameWonFragment
. A mensagem do sistema aparece na tela Congratulations,
dizendo "NumCorrect: 3, NumQuestions: 3".numQuestions
para 1
no GameFragment.kt
Arquivo Kotlin.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:
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())
}
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())
}
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())
}
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.
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.
GameWonFragment.kt
Kotlin.onCreateView()
, antes do return
, chame o método setHasOptionsMenu()
e passe true
: setHasOptionsMenu(true)
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.
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. 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
}
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())
}
winner_menu.xml
. Substitua
onCreateOptionsMenu()
para inflar o winner_menu
. 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)
}
}
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)
}
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:
NavDirection
correspondente. Você adiciona a classe NavDirection
ao código do fragmento e, em seguida, usa a
classe para passar argumentos entre o fragmento e outros fragmentos.NavDirection
representam a navegação de todas as ações do aplicativo.Intenções implícitas:
ACTION_SEND
.Intent()
estão disponíveis para ajudá-lo a construir
intents. Funcionalidade de compartilhamento:
Intent
seria
Intent.ACTION_SEND
.setHasOptionsMenu()
como true
no código do
fragmento.onCreateOptionsMenu()
para inflar o menu. onOptionsItemSelected()
para usar startActivity()
para enviar o
Intent
para outros aplicativos que podem manipulá-lo. 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.
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.
O que o plug-in Safe Args Gradle faz? Selecione tudo que se aplica:
Navigation
que você pode editar para simplificar a passagem de parâmetros entre
fragmentos.O que é uma intenção implícita?
Comece a próxima lição:
Para obter enlaces para outros tutoriais neste curso, consulte a página de destino dos tutoriais Fundamentos de Android em Kotlin.