Este codelab faz parte do curso Conceitos básicos do Kotlin para Android. Você vai aproveitar mais este curso se fizer os codelabs em sequência. Todos os codelabs do curso estão listados na página inicial dos codelabs de princípios básicos do Kotlin para Android.
Introdução
Quase todos os apps Android que você cria precisam se conectar à Internet em algum momento. Neste codelab e nos seguintes, você vai criar um app que se conecta a um serviço da Web para buscar e mostrar dados.  Você também vai usar o que aprendeu em codelabs anteriores sobre ViewModel, LiveData e RecyclerView. 
Neste codelab, você vai usar bibliotecas desenvolvidas pela comunidade para criar a camada de rede. Isso simplifica muito a busca de dados e imagens, além de ajudar o app a seguir algumas práticas recomendadas do Android, como carregar imagens em uma linha de execução em segundo plano e armazenar em cache as imagens carregadas. Para as seções assíncronas ou sem bloqueio no código, como a comunicação com a camada de serviços da Web, você vai modificar o app para usar as corrotinas do Kotlin. Você também vai atualizar a interface do usuário do app se a Internet estiver lenta ou indisponível para informar o usuário sobre o que está acontecendo.
O que você já precisa saber
- Como criar e usar fragmentos.
 - Como navegar entre fragmentos e usar 
safeArgspara transmitir dados entre eles. - Como usar componentes de arquitetura, incluindo 
ViewModel,ViewModelProvider.Factory,LiveDatae transformaçõesLiveData. - Como usar corrotinas para tarefas de longa duração.
 
O que você vai aprender
- O que é um serviço REST da Web.
 - Como usar a biblioteca Retrofit (link em inglês) para se conectar a um serviço da Web REST na Internet e receber uma resposta.
 - Como usar a biblioteca Moshi (link em inglês) para analisar a resposta JSON em um objeto de dados.
 
O que você aprenderá
- Como modificar um app inicial para fazer uma solicitação de API de serviço da Web e lidar com a resposta.
 - Como implementar uma camada de rede para o app usando a biblioteca Retrofit.
 - Como analisar a resposta JSON do serviço da Web nos dados dinâmicos do app com a biblioteca Moshi.
 - Como usar a compatibilidade da biblioteca Retrofit para corrotinas para simplificar o código.
 
Neste codelab (e nos seguintes), você vai trabalhar com um app inicial chamado MarsRealEstate, que mostra propriedades à venda em Marte. Esse app se conecta a um serviço da Web para recuperar e mostrar os dados da propriedade, incluindo detalhes como o preço e se ela está disponível para venda ou aluguel. As imagens que representam cada propriedade são fotos reais de Marte capturadas por rovers da NASA.

A versão do app que você compilar neste codelab não terá muita beleza visual: ele se concentra na parte da camada de rede do app para se conectar à Internet e fazer o download dos dados brutos de propriedade usando um serviço da Web. Para garantir que os dados sejam recuperados e analisados corretamente, basta exibir o número de propriedades em Marte em uma visualização de texto:

.
A arquitetura do app MarsRealEstate tem dois módulos principais:
- Um fragmento de visão geral, que contém uma grade de imagens de propriedades em miniatura, criada com um 
RecyclerView. - Um fragmento de visualização de detalhes, que contém informações sobre cada propriedade.
 

O app tem um ViewModel para cada fragmento. Neste codelab, você vai criar uma camada para o serviço de rede, e o ViewModel vai se comunicar diretamente com essa camada de rede.  Isso é semelhante ao que você fez em codelabs anteriores quando o ViewModel se comunicou com o banco de dados Room.
A visão geral ViewModel é responsável por fazer a chamada de rede para acessar as informações imobiliárias de Marte. O detalhe ViewModel contém detalhes sobre o único imóvel em Marte exibido no fragmento de detalhes.  Para cada ViewModel, você usa LiveData com vinculação de dados compatível com o ciclo de vida para atualizar a interface do app quando os dados mudam.  
Você usa o componente Navigation para navegar entre os dois fragmentos e transmitir a propriedade selecionada como um argumento.
Nesta tarefa, você vai baixar e executar o app inicial do MarsRealEstate e conhecer a estrutura do projeto.
Etapa 1: conhecer fragmentos e navegação
- Faça o download do app inicial MarsRealEstate (link em inglês) e abra-o no Android Studio.
 - Analise 
app/java/MainActivity.kt. O app usa fragmentos para as duas telas. Portanto, a única tarefa da atividade é carregar o layout dela. - Analise 
app/res/layout/activity_main.xml. O layout da atividade é o host dos dois fragmentos, definidos no arquivo de navegação. Esse layout cria uma instância deNavHostFragmente do controlador de navegação associado com o recursonav_graph. - Abra 
app/res/navigation/nav_graph.xml. Aqui você pode ver a relação de navegação entre os dois fragmentos. O gráfico de navegaçãoStartDestinationaponta para ooverviewFragment, então o fragmento de visão geral é instanciado quando o app é iniciado. 
Etapa 2: conferir os arquivos de origem do Kotline a vinculação de dados
- No painel Project, clique para expandir app > java. O app MarsRealEstate tem três pastas de pacote:  
detail,networkeoverview. Eles correspondem aos três componentes principais do app: os fragmentos de visão geral e detalhes e o código da camada de rede.
   - Abra 
app/java/overview/OverviewFragment.kt. OOverviewFragmentinicializa lentamente oOverviewViewModel, o que significa que oOverviewViewModelé criado na primeira vez que é usado. - Examine o método 
onCreateView(). Esse método infla o layoutfragment_overviewusando a vinculação de dados, define o proprietário do ciclo de vida da vinculação como ele mesmo (this) e define a variávelviewModelno objetobindingcomo ele. Como definimos o proprietário do ciclo de vida, qualquerLiveDatausado na vinculação de dados será observado automaticamente para mudanças, e a interface será atualizada de acordo. - Abra 
app/java/overview/OverviewViewModel. Como a resposta é umLiveDatae definimos o ciclo de vida para a variável de vinculação, qualquer mudança nela vai atualizar a interface do app. - Examine o bloco 
init. Quando oViewModelé criado, ele chama o métodogetMarsRealEstateProperties(). - Examine o método 
getMarsRealEstateProperties(). Neste app inicial, esse método contém uma resposta de marcador. O objetivo deste codelab é atualizar a respostaLiveDatanoViewModelusando dados reais da Internet. - Abra 
app/res/layout/fragment_overview.xml. Este é o layout do fragmento de visão geral com que você trabalha neste codelab, e ele inclui a vinculação de dados para o modelo de visualização. Ele importa oOverviewViewModele vincula a resposta doViewModela umTextView. Em codelabs futuros, você vai substituir a visualização de texto por uma grade de imagens em umRecyclerView. - Compile e execute o app. Tudo o que você vê na versão atual do app é a resposta inicial: "Defina a resposta da API Mars aqui!"
 
 
Os dados imobiliários de Marte são armazenados em um servidor da Web como um serviço da Web REST. Os serviços da Web que usam a arquitetura REST são criados com componentes e protocolos padrão da Web.
Você faz uma solicitação a um serviço da Web de maneira padronizada usando URIs. O famoso URL da Web é, na verdade, um tipo de URI, e ambos são usados alternadamente neste curso. Por exemplo, no app desta lição, você recupera todos os dados do seguinte servidor:
https://android-kotlin-fun-mars-server.appspot.com
Se você digitar o URL a seguir no navegador, vai receber uma lista de todas as propriedades imobiliárias disponíveis em Marte.
https://android-kotlin-fun-mars-server.appspot.com/realestate
A resposta de um serviço da Web geralmente é formatada em JSON, um formato de intercâmbio para representar dados estruturados. Você vai aprender mais sobre JSON na próxima tarefa, mas a explicação curta é que um objeto JSON é uma coleção de pares de chave-valor, às vezes chamada de dicionário, mapa de hash ou matriz associativa. Uma coleção de objetos JSON é uma matriz JSON, e é essa matriz que você recebe como resposta de um serviço da Web.
Para acessar esses dados no app, ele precisa estabelecer uma conexão de rede e se comunicar com o servidor. Em seguida, ele recebe e analisa os dados de resposta em um formato que pode ser usado. Neste codelab, vamos usar uma biblioteca de cliente REST chamada Retrofit para fazer essa conexão.
Etapa 1: adicionar dependências do Retrofit ao Gradle
- Abra o arquivo build.gradle (Module: app).
 - Na seção 
dependencies, adicione estas linhas para as bibliotecas Retrofit: 
implementation "com.squareup.retrofit2:retrofit:$version_retrofit"
implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"
Os números de versão são definidos separadamente no arquivo Gradle do projeto. A primeira dependência é para a biblioteca Retrofit 2, e a segunda é para o conversor escalar da Retrofit.  Esse conversor permite que a Retrofit retorne o resultado JSON como uma String. As duas bibliotecas trabalham juntas.
- Clique em Sync Now para recriar o projeto com as novas dependências.
 
Etapa 2: implementar MarsApiService
A Retrofit cria uma API de rede para o app com base no conteúdo do serviço da Web. Ela busca dados do serviço da Web e os encaminha usando uma biblioteca de conversor separada, que sabe como decodificar os dados e retorná-los na forma de objetos úteis. A Retrofit inclui suporte integrado para formatos de dados da Web conhecidos, como XML e JSON. A Retrofit cria a maior parte da camada de rede para você, incluindo detalhes importantes, como executar solicitações em linhas de execução de segundo plano.
A classe MarsApiService contém a camada de rede do app. Ou seja, essa é a API que seu ViewModel vai usar para se comunicar com o serviço da Web.  Essa é a classe em que você vai implementar a API de serviço Retrofit.  
- Abra 
app/java/network/MarsApiService.kt. No momento, o arquivo contém apenas uma coisa: uma constante para o URL base do serviço da Web. 
private const val BASE_URL = 
   "https://android-kotlin-fun-mars-server.appspot.com"- Logo abaixo dessa constante, use um builder da Retrofit para criar um objeto da Retrofit.  Importe 
retrofit2.Retrofiteretrofit2.converter.scalars.ScalarsConverterFactoryquando solicitado. 
private val retrofit = Retrofit.Builder()
   .addConverterFactory(ScalarsConverterFactory.create())
   .baseUrl(BASE_URL)
   .build()
A Retrofit precisa de pelo menos duas coisas para criar uma API de serviços da Web: o URI base do serviço da Web e uma fábrica de conversores.  O conversor informa à Retrofit o que fazer com os dados recebidos do serviço da Web.  Nesse caso, você quer que a Retrofit busque uma resposta JSON do serviço da Web e retorne-a como uma String.  A Retrofit tem um ScalarsConverter que aceita strings e outros tipos primitivos, portanto, você chama addConverterFactory() no builder com uma instância de ScalarsConverterFactory.  Por fim, chame build() para criar o objeto Retrofit.
- Logo abaixo da chamada para o builder da Retrofit, defina uma interface que estabeleça como a Retrofit se comunica com o servidor da Web usando solicitações HTTP.  Importe 
retrofit2.http.GETeretrofit2.Callquando solicitado. 
interface MarsApiService {
    @GET("realestate")
    fun getProperties():
            Call<String>
}No momento, o objetivo é receber a string de resposta JSON do serviço da Web, e você só precisa de um método para isso: getProperties().  Para informar à Retrofit o que esse método precisa fazer, use uma anotação @GET e especifique o caminho ou endpoint para esse método de serviço da Web.  Nesse caso, o endpoint tem o nome realestate. Quando o método getProperties() é invocado, a Retrofit anexa o endpoint realestate ao URL base (que você definiu no builder da Retrofit) e cria um objeto Call. Esse objeto Call é usado para iniciar a solicitação.
- Abaixo da interface 
MarsApiService, defina um objeto público chamadoMarsApipara inicializar o serviço da Retrofit. 
object MarsApi {
    val retrofitService : MarsApiService by lazy { 
       retrofit.create(MarsApiService::class.java) }
}O método create() do Retrofit cria o próprio serviço com a interface MarsApiService.  Como essa chamada é custosa e o app precisa de apenas uma instância do serviço Retrofit, você expõe o serviço ao restante do app usando um objeto público chamado MarsApi e inicializa o serviço Retrofit de forma lenta. Agora que toda a configuração foi feita, cada vez que o app chamar MarsApi.retrofitService,  ele vai receber um objeto Singleton da Retrofit que implementa MarsApiService.
Etapa 3: chamar o serviço da Web no OverviewViewModel
- Abra 
app/java/overview/OverviewViewModel.kt. Role para baixo até o métodogetMarsRealEstateProperties(). 
private fun getMarsRealEstateProperties() {
   _response.value = "Set the Mars API Response here!"
}É o método em que você vai chamar o serviço da Retrofit e processar a string JSON retornada. No momento, há apenas uma string de marcador de posição para a resposta.
- Exclua a linha do marcador de posição que define a resposta como "Defina a resposta da API de Marte aqui!"
 - Em 
getMarsRealEstateProperties(), adicione o código mostrado abaixo. Importeretrofit2.Callbackecom.example.android.marsrealestate.network.MarsApiquando solicitado.
O métodoMarsApi.retrofitService.getProperties()retorna um objetoCall. Em seguida, chameenqueue()nesse objeto para iniciar a solicitação de rede em uma linha de execução em segundo plano. 
MarsApi.retrofitService.getProperties().enqueue( 
   object: Callback<String> {
})- Clique na palavra 
object, que está sublinhada em vermelho. Selecione Code > Implement methods. SelecioneonResponse()eonFailure()na lista.
O Android Studio adiciona o código com TODOs em cada método: 
override fun onFailure(call: Call<String>, t: Throwable) {
       TODO("not implemented") 
}
override fun onResponse(call: Call<String>, 
   response: Response<String>) {
       TODO("not implemented") 
}- Em 
onFailure(), exclua o TODO e defina a_responsecomo uma mensagem de falha, conforme mostrado abaixo. O_responseé uma stringLiveDataque determina o que é mostrado na visualização de texto. Cada estado precisa atualizar o_responseLiveData.
O callbackonFailure()é chamado quando a resposta do serviço da Web falha. Para essa resposta, defina o status_responsecomo"Failure: "concatenado com a mensagem do argumentoThrowable. 
override fun onFailure(call: Call<String>, t: Throwable) {
   _response.value = "Failure: " + t.message
}- Em 
onResponse(), exclua o TODO e defina_responsecomo o corpo da resposta. O callbackonResponse()é chamado quando a solicitação é bem-sucedida e o serviço da Web retorna uma resposta. 
override fun onResponse(call: Call<String>, 
   response: Response<String>) {
      _response.value = response.body()
}Etapa 4: definir a permissão de Internet
- Compile e execute o app MarsRealEstate.  Observe que ele fecha imediatamente com um erro. 
   - Clique na guia Logcat no Android Studio e observe o erro no registro, que começa com uma linha como esta:
 
Process: com.example.android.marsrealestate, PID: 10646 java.lang.SecurityException: Permission denied (missing INTERNET permission?)
A mensagem de erro informa que o app pode não ter a permissão INTERNET. Conectar-se à Internet gera preocupações de segurança. Por isso, os apps não têm conectividade com a Internet por padrão. É necessário informar explicitamente ao Android que o app precisa de acesso à Internet.
- Abra 
app/manifests/AndroidManifest.xml. Adicione esta linha imediatamente antes da tag<application>: 
<uses-permission android:name="android.permission.INTERNET" />- Compile e execute o app novamente.  Se tudo estiver funcionando corretamente com sua conexão de Internet, você verá um texto JSON com dados da propriedade de Marte.

 - Toque no botão Voltar do dispositivo ou emulador para fechar o app.
 - Coloque o dispositivo ou emulador no modo avião e abra o app novamente no menu Recentes ou reinicie-o no Android Studio.
 

- Desative o modo avião novamente.
 
Você receberá uma resposta JSON do serviço da Web de Marte, o que é um ótimo começo. Mas o que você realmente precisa são objetos Kotlin, não uma string JSON longa. Há uma biblioteca chamada Moshi (link em inglês), que é um analisador JSON do Android que converte uma string JSON em objetos Kotlin. A Retrofit tem um conversor que funciona com a Moshi, então ela é uma ótima biblioteca para o objetivo deste codelab.
Nesta tarefa, você vai usar a biblioteca Moshi com a Retrofit para analisar a resposta JSON do serviço da Web em objetos Kotlin úteis de propriedades de Marte. Para isso, é necessário fazer uma modificação no app para que ele mostre o número de propriedades de Marte retornadas, em vez da resposta JSON bruta.
Etapa 1: adicionar dependências da biblioteca Moshi
- Abra o arquivo build.gradle (Module: app).
 - Na seção de dependências, adicione o código abaixo para incluir as dependências da Moshi. Assim como no Retrofit, 
$version_moshié definido separadamente no arquivo Gradle do projeto. Essas dependências adicionam suporte à biblioteca JSON principal do Moshi e à compatibilidade do Moshi com Kotlin. 
implementation "com.squareup.moshi:moshi:$version_moshi"
implementation "com.squareup.moshi:moshi-kotlin:$version_moshi"- Localize a linha do conversor escalar da Retrofit no bloco 
dependencies: 
implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"- Mude essa linha para usar 
converter-moshi: 
implementation "com.squareup.retrofit2:converter-moshi:$version_retrofit"- Clique em Sync Now para recriar o projeto com as novas dependências.
 
Etapa 2: implementar a classe de dados MarsProperty
Confira um exemplo de entrada da resposta JSON recebida do serviço da Web:
[{"price":450000,
"id":"424906",
"type":"rent",
"img_src":"http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631300305227E03_DXXX.jpg"},
...]A resposta JSON mostrada acima é uma matriz, indicada por colchetes.  A matriz contém objetos JSON, que estão entre chaves.  Cada objeto contém um conjunto de pares nome-valor, separados por dois-pontos. Os nomes ficam entre aspas. Os valores podem ser números ou strings, e as strings também são colocadas entre aspas. Por exemplo, o price dessa propriedade é US $450.000,e o img_src é um URL, que é o local do arquivo de imagem no servidor. 
No exemplo acima, cada entrada de propriedade de Marte tem estes pares de chave e valor JSON:
price: o preço da propriedade em Marte, como um número.id: o ID da propriedade, como uma string.type:"rent"ou"buy".img_src: o URL da imagem como uma string.
A Moshi analisa esses dados JSON e os converte em objetos Kotlin. Para fazer isso, ele precisa ter uma classe de dados Kotlin para armazenar os resultados analisados. Portanto, a próxima etapa é criar essa classe.
- Abra 
app/java/network/MarsProperty.kt. - Substitua a definição da classe 
MarsPropertypelo seguinte código: 
data class MarsProperty(
   val id: String, val img_src: String,
   val type: String,
   val price: Double
)Cada uma das variáveis na classe MarsProperty corresponde a um nome de chave no objeto JSON.  Para corresponder aos tipos no JSON, use objetos String para todos os valores, exceto price, que é um Double.  Um Double pode ser usado para representar qualquer número JSON.
Quando a Moshi analisa o JSON, ela faz a correspondência das chaves por nome e preenche os objetos de dados com os valores corretos.
- Substitua a linha da chave 
img_srcpela linha mostrada abaixo. Importecom.squareup.moshi.Jsonquando solicitado. 
@Json(name = "img_src") val imgSrcUrl: String,Às vezes, os nomes de chave em uma resposta JSON podem criar propriedades Kotlin confusas ou não corresponder ao seu estilo de programação. Por exemplo, no arquivo JSON, a chave img_src usa um sublinhado, enquanto as propriedades Kotlin geralmente usam letras maiúsculas e minúsculas ("letras concatenadas"). 
Para usar nomes de variáveis na sua classe de dados que sejam diferentes dos nomes de chave da resposta JSON, use a anotação @Json. Neste exemplo, o nome da variável na classe de dados é imgSrcUrl. A variável é mapeada para o atributo JSON img_src usando @Json(name = "img_src").
Etapa 3: atualizar MarsApiService e OverviewViewModel
Com a classe de dados MarsProperty no lugar, agora é possível atualizar a API de rede e ViewModel para incluir os dados do Moshi.  
- Abra 
network/MarsApiService.kt. É possível que você veja erros de classe ausente paraScalarsConverterFactory. Isso ocorre devido à mudança da dependência da Retrofit feita na etapa 1. Você vai corrigir esses erros em breve. - Na parte de cima do arquivo, antes do builder da Retrofit, adicione o seguinte código para criar a instância do Moshi.  Importe 
com.squareup.moshi.Moshiecom.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactoryquando solicitado. 
private val moshi = Moshi.Builder()
   .add(KotlinJsonAdapterFactory())
   .build()Semelhante ao que você fez com a Retrofit, aqui você cria um objeto moshi usando o builder da Moshi.  Para que as anotações da Moshi funcionem corretamente com o Kotlin, adicione a KotlinJsonAdapterFactory e chame build().  
- Mude o builder da Retrofit para usar a 
MoshiConverterFactoryem vez daScalarConverterFactorye transmita a instânciamoshique você acabou de criar. Importeretrofit2.converter.moshi.MoshiConverterFactoryquando solicitado. 
private val retrofit = Retrofit.Builder()
   .addConverterFactory(MoshiConverterFactory.create(moshi))
   .baseUrl(BASE_URL)
   .build()- Exclua também a importação de 
ScalarConverterFactory. 
Código a ser excluído:
import retrofit2.converter.scalars.ScalarsConverterFactory- Atualize a interface 
MarsApiServicepara que a Retrofit retorne uma lista de objetosMarsProperty, em vez de retornar umaCall<String>. 
interface MarsApiService {
   @GET("realestate")
   fun getProperties():
      Call<List<MarsProperty>>
}- Abra 
OverviewViewModel.kt. Role para baixo até a chamada degetProperties().enqueue()no métodogetMarsRealEstateProperties(). - Mude o argumento para 
enqueue()deCallback<String>paraCallback<List<MarsProperty>>. Importecom.example.android.marsrealestate.network.MarsPropertyquando solicitado. 
MarsApi.retrofitService.getProperties().enqueue( 
   object: Callback<List<MarsProperty>> {- Em 
onFailure(), mude o argumento deCall<String>paraCall<List<MarsProperty>>: 
override fun onFailure(call: Call<List<MarsProperty>>, t: Throwable) {- Faça a mesma mudança nos dois argumentos para 
onResponse(): 
override fun onResponse(call: Call<List<MarsProperty>>, 
   response: Response<List<MarsProperty>>) {- No corpo de 
onResponse(), substitua a atribuição atual a_response.valuepela atribuição mostrada abaixo. Como oresponse.body()agora é uma lista de objetosMarsProperty, o tamanho dessa lista é o número de propriedades que foram analisadas. Essa mensagem de resposta imprime esse número de propriedades: 
_response.value = 
   "Success: ${response.body()?.size} Mars properties retrieved"- Verifique se o modo avião está desativado.  Compile e execute o app. Desta vez, a mensagem vai mostrar o número de propriedades retornadas do serviço da Web:

 
Agora, o serviço da API Retrofit está em execução, mas usa um callback com dois métodos de callback que você precisou implementar. Um método processa o sucesso e outro processa a falha, e o resultado da falha informa exceções. Seu código seria mais eficiente e fácil de ler se você pudesse usar corrotinas com tratamento de exceções em vez de callbacks. A Retrofit tem uma biblioteca que integra corrotinas.
Nesta tarefa, você vai converter o serviço de rede e o ViewModel para usar corrotinas.  
Etapa 1: adicionar dependências de corrotinas
- Abra o arquivo build.gradle (Module: app).
 - Na seção de dependências, adicione suporte às bibliotecas principais de corrotinas do Kotlin e à biblioteca de corrotinas do Retrofit:
 
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_kotlin_coroutines" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_kotlin_coroutines" implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$version_retrofit_coroutines_adapter"
- Clique em Sync Now para recriar o projeto com as novas dependências.
 
Etapa 2: atualizar MarsApiService e OverviewViewModel
- Em 
MarsApiService.kt, atualize o builder da Retrofit para usar aCoroutineCallAdapterFactory. O builder completo agora vai ficar assim: 
private val retrofit = Retrofit.Builder()
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .baseUrl(BASE_URL)
        .build()Os adaptadores de chamada adicionam a capacidade de a Retrofit criar APIs que retornam algo diferente da classe Call padrão.  Nesse caso, o CoroutineCallAdapterFactory permite substituir o objeto Call que getProperties() retorna por um objeto Deferred.
- No método 
getProperties(), mudeCall<List<MarsProperty>>paraDeferred<List<MarsProperty>>. Importekotlinx.coroutines.Deferredquando solicitado. O métodogetProperties()completo fica assim: 
@GET("realestate")
fun getProperties():
   Deferred<List<MarsProperty>>A interface Deferred define um trabalho de corrotina que retorna um valor de resultado (Deferred herda de Job). A interface Deferred inclui um método chamado await(), que faz com que seu código espere sem bloquear até que o valor esteja pronto. Depois, esse valor é retornado. 
- Abra 
OverviewViewModel.kt. Pouco antes do blocoinit, adicione um job de corrotina: 
private var viewModelJob = Job()- Crie um escopo de corrotina para esse novo job usando o dispatcher principal:
 
private val coroutineScope = CoroutineScope(
   viewModelJob + Dispatchers.Main )O agente Dispatchers.Main usa a linha de execução da interface para o trabalho dele.  Como o Retrofit faz todo o trabalho em uma linha de execução em segundo plano, não há motivo para usar outra linha de execução para o escopo. Isso permite atualizar facilmente o valor do MutableLiveData quando você recebe um resultado.
- Exclua todo o código dentro de 
getMarsRealEstateProperties(). Aqui, você vai usar corrotinas em vez da chamada paraenqueue()e os callbacksonFailure()eonResponse(). - No método 
getMarsRealEstateProperties(), inicie a corrotina: 
coroutineScope.launch { 
}
Para usar o objeto Deferred que a Retrofit retorna para a tarefa de rede, você precisa estar em uma corrotina. Por isso, inicie a corrotina que você acabou de criar.  Você ainda está executando código na linha de execução principal, mas agora está deixando as corrotinas gerenciarem a simultaneidade.
- No bloco de inicialização, chame 
getProperties()no objetoretrofitService: 
var getPropertiesDeferred = MarsApi.retrofitService.getProperties()Chamar getProperties() do serviço MarsApi cria e inicia a chamada de rede em uma linha de execução em segundo plano, retornando o objeto Deferred para essa tarefa. 
- Ainda no bloco de inicialização, adicione um bloco 
try/catchpara processar exceções: 
try {
} catch (e: Exception) {
  
}- No bloco 
try {}, chameawait()no objetoDeferred: 
var listResult = getPropertiesDeferred.await()Chamar await() no objeto Deferred retorna o resultado da chamada de rede quando o valor está pronto. O método await() não é bloqueador. Portanto, o serviço da API Mars recupera os dados da rede sem bloquear a linha de execução atual, o que é importante porque estamos no escopo da linha de execução da interface. Quando a tarefa é concluída, o código continua a execução de onde parou.  Isso está dentro do try {} para que você possa capturar exceções.  
- Ainda dentro do bloco 
try {}, depois do métodoawait(), atualize a mensagem de resposta para a resposta bem-sucedida: 
_response.value = 
   "Success: ${listResult.size} Mars properties retrieved"- No bloco 
catch {}, gerencie a resposta da falha: 
_response.value = "Failure: ${e.message}"
O método getMarsRealEstateProperties() completo agora ficará assim:
private fun getMarsRealEstateProperties() {
   coroutineScope.launch {
       var getPropertiesDeferred = 
          MarsApi.retrofitService.getProperties()
       try {          
           _response.value = 
              "Success: ${listResult.size} Mars properties retrieved"
       } catch (e: Exception) {
           _response.value = "Failure: ${e.message}"
       }
   }
}- Na parte de baixo da classe, adicione um callback 
onCleared()com este código: 
override fun onCleared() {
   super.onCleared()
   viewModelJob.cancel()
}O carregamento de dados precisa ser interrompido quando o ViewModel é destruído, porque o OverviewFragment que usa esse ViewModel desaparece. Para interromper o carregamento quando o ViewModel for destruído, substitua onCleared() para cancelar o job.
- Compile e execute o app. Você vai ter o mesmo resultado da tarefa anterior (um relatório do número de propriedades), mas com um código e um tratamento de erros mais simples.
 
Projeto do Android Studio: MarsRealEstateNetwork (link em inglês)
Serviços REST da Web
- Um serviço da Web é um serviço na Internet que permite que o app faça solicitações e receba dados de volta.
 - Os serviços comuns da Web usam uma arquitetura REST (link em inglês). Os serviços da Web que oferecem arquitetura REST são conhecidos como serviços RESTful. Serviços RESTful da Web são criados usando componentes e protocolos padrão da Web.
 - Você faz uma solicitação a um serviço REST da Web de maneira padronizada usando URIs.
 - Para usar um serviço da Web, um app precisa estabelecer uma conexão de rede e se comunicar com o serviço. Em seguida, o app precisa receber e analisar os dados de resposta em um formato que ele possa usar.
 - A biblioteca Retrofit (link em inglês) é uma biblioteca de cliente que permite que o app faça solicitações a um serviço REST da Web.
 - Use os conversores para informar à Retrofit o que fazer com os dados que ela envia ao serviço da Web e os dados que ela recebe do serviço.  Por exemplo, o conversor 
ScalarsConvertertrata os dados do serviço da Web como umaStringou outro primitivo. - Para permitir que seu app faça conexões com a Internet, adicione a permissão 
"android.permission.INTERNET"ao manifesto do Android. 
Análise JSON
- A resposta de um serviço da Web geralmente é formatada em JSON, um formato de intercâmbio comum para representar dados estruturados.
 - Um objeto JSON é uma coleção de pares de chave-valor. Essa coleção às vezes é chamada de dicionário, mapa de hash ou matriz associativa.
 - Uma coleção de objetos JSON é uma matriz JSON. Você recebe uma matriz JSON como resposta de um serviço da Web.
 - As chaves em um par de chave-valor ficam entre aspas. Os valores podem ser números ou strings. As strings também ficam entre aspas.
 - A biblioteca Moshi (link em inglês) é um analisador JSON do Android que converte uma string JSON em objetos Kotlin. A Retrofit tem um conversor que funciona com a Moshi.
 - A Moshi combina as chaves em uma resposta JSON com as propriedades de um objeto de dados com o mesmo nome.
 - Para usar um nome de propriedade diferente para uma chave, use a anotação 
@Jsone o nome da chave JSON para anotar essa propriedade. 
Retrofit e corrotinas
- Os adaptadores de chamada permitem que o Retrofit crie APIs que retornam algo diferente da classe 
Callpadrão. Use a classeCoroutineCallAdapterFactorypara substituir oCallpor uma corrotinaDeferred. - Use o método 
await()no objetoDeferredpara fazer com que o código da corrotina aguarde sem bloqueio até que o valor esteja pronto. Depois, o valor é retornado. 
Curso da Udacity:
Documentação do desenvolvedor Android:
Documentação do Kotlin:
- Codelab de corrotinas
 - Documentação oficial de corrotinas (link em inglês)
 - Contexto e agentes de corrotinas (link em inglês)
 
Outro:
- Retrofit (link em inglês)
 - Moshi (link em inglês)
 - Moshi com Retrofit no Kotlin (link em inglês)
 
Esta seção lista as possíveis atividades de dever de casa para os alunos que estão fazendo este codelab como parte de um curso ministrado por um professor. Cabe ao professor fazer o seguinte:
- Atribuir o dever de casa, se necessário.
 - Informar aos alunos como enviar deveres de casa.
 - Atribuir nota aos deveres de casa.
 
Os professores podem usar essas sugestões o quanto quiserem, podendo passar os exercícios que acharem mais apropriados como dever de casa.
Se você estiver seguindo este codelab por conta própria, sinta-se à vontade para usar esses deveres de casa para testar seu conhecimento.
Responda estas perguntas
Pergunta 1
Quais são os dois principais itens de que a Retrofit precisa para criar uma API de serviços da Web?
▢ O URI de base do serviço da Web e uma consulta GET.
▢ O URI de base do serviço da Web e uma fábrica de conversores.
▢ Uma conexão de rede com o serviço da Web e um token de autorização.
▢ Uma fábrica de conversores e um analisador para a resposta.
Pergunta 2
Qual é a finalidade da biblioteca Moshi?
▢ Para extrair dados de um serviço da Web.
▢ Interagir com a Retrofit para fazer uma solicitação de serviço da Web.
▢ Analisar uma resposta JSON de um serviço da Web em objetos de dados Kotlin.
▢ Renomear objetos Kotlin para corresponder às chaves na resposta JSON.
Pergunta 3
Para que servem os adaptadores de chamadas da Retrofit?
▢ Eles permitem que a Retrofit use corrotinas.
▢ Eles adaptam a resposta do serviço da Web em objetos de dados Kotlin.
▢ Eles mudam uma chamada da Retrofit para uma chamada de serviço da Web.
▢ Eles adicionam a capacidade de retornar algo diferente da classe Call padrão na Retrofit.
Comece a próxima lição: 
Para acessar links de outros codelabs neste curso, consulte a página inicial dos codelabs de conceitos básicos do Kotlin para Android.