Introdução

Nos tutoriais anteriores para esta lição, você aprendeu como obter dados sobre imóveis em Marte a partir de um serviço da web e como criar um RecyclerView com um layout de grade para carregar e exibir imagens desses dados. Neste tutorial, você conclui o aplicativo MarsRealEstate implementando a capacidade de filtrar as propriedades de Marte por estarem disponíveis para aluguel ou compra. Você também cria uma vista de detalhes para que, se o usuário tocar em uma foto de propriedade na visão geral, eles vejam uma vista de detalhes com detalhes sobre essa propriedade.

O que já deveria saber

O que aprenderá

O que fará

Neste tutorial (e tutoriais relacionados), você trabalha com um aplicativo chamado MarsRealEstate, que mostra propriedades à venda em Marte. Este aplicativo se conecta a um servidor de Internet para recuperar e exibir dados de propriedade, incluindo detalhes como o preço e se a propriedade está disponível para venda ou aluguel. As imagens que representam cada propriedade são fotos da vida real de Marte, capturadas pelos robôs de Marte da NASA. Nos tutoriais anteriores, você criou um RecyclerView com um layout de grade para todas as fotos de propriedade:

Nesta versão do aplicativo, você trabalha com o tipo de propriedade (alugar versus comprar) e adiciona um ícone ao layout de grade para marcar as propriedades que estão à venda:

Você modifica o menu de opções do aplicativo para filtrar a grade para mostrar apenas as propriedades que estão para alugar ou vender:

E, finalmente, você cria uma vista de detalhes para uma propriedade individual e conecta os ícones na grade de visão geral a esse fragmento de detalhe com navegação:

Até agora, a única parte dos dados da propriedade de Marte que você usou foi o URL da imagem da propriedade. Mas os dados de propriedade - que você definiu na classe MarsProperty - também incluem um ID, um preço e um tipo (aluguel ou venda). Para refrescar sua memória, aqui está um snippet dos dados JSON que você obtém do serviço da web:

{
   "price":8000000,
   "id":"424908",
   "type":"rent",
   "img_src": "http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631290305226E03_DXXX.jpg"
},

Nesta tarefa, você começa a trabalhar com o tipo de propriedade Marte para adicionar uma imagem de cifrão às propriedades na página de visão geral que estão à venda.

Etapa 1: Atualize MarsProperty para incluir o tipo

A classe MarsProperty define a estrutura de dados para cada propriedade fornecida pelo serviço da web. Em um tutorial anterior, você usou a biblioteca Moshi para analisar a resposta JSON bruta do serviço da web Mars em objetos de dados MarsProperty individuais.

Nesta etapa, você adiciona alguma lógica à classe MarsProperty para indicar se uma propriedade está para alugar ou não (isto é, se o tipo é a string "rent" ou "buy"). Você usará essa lógica em mais de um lugar, então é melhor tê-la aqui na classe de dados do que replicá-la.

  1. Abra o aplicativo MarsRealEstate do último tutorial. (Você pode fazer download do MarsRealEstateGrid se não tiver o aplicativo).
  2. Abra network/MarsProperty.kt. Adicione um corpo à definição de classe MarsProperty e adicione um getter personalizado para isRental que retorna true se o objeto for do tipo "rent".
data class MarsProperty(
       val id: String,
       @Json(name = "img_src") val imgSrcUrl: String,
       val type: String,
       val price: Double)  {
   val isRental
       get() = type == "rent"
}

Etapa 2: Atualize o layout do item da grade

Agora você atualiza o layout do item para a grade de imagens para mostrar um desenho de cifrão apenas nas imagens de propriedades que estão à venda:

Com as expressões de vinculação de dados, você pode fazer este teste inteiramente no layout XML para os itens de grade.

  1. Abra res/layout/grid_view_item.xml. Este é o arquivo de layout para cada célula individual no layout de grade para o RecyclerView. Atualmente, o arquivo contém apenas o elemento <ImageView> para a imagem de propriedade.
  2. Dentro do elemento <data>, adicione um elemento <import> para a classe View. Você usa importações quando deseja usar componentes de uma classe dentro de uma expressão de vinculação de dados em um arquivo de layout. Neste caso, você usará as constantes View.GONE e View.VISIBLE, então você precisa acessar a classe View.
<import type="android.view.View"/>
  1. Cerque a vista da imagem inteira com um FrameLayout, para permitir que o drawable do cifrão seja empilhado sobre a imagem da propriedade.
<FrameLayout
   android:layout_width="match_parent"
   android:layout_height="170dp">
             <ImageView 
                    android:id="@+id/mars_image"
            ...
</FrameLayout>
  1. Para ImageView, altere o atributo android:layout_height para match_parent, para preencher o novo pai FrameLayout.
android:layout_height="match_parent"
  1. Adicione um segundo elemento <ImageView> logo abaixo do primeiro, dentro do FrameLayout. Use a definição mostrada abaixo. Esta imagem aparece no canto inferior direito do item de grade, no topo da imagem de Marte, e usa o drawable definido em res/drawable/ic_for_sale_outline.xml para o ícone de cifrão.
<ImageView
   android:id="@+id/mars_property_type"
   android:layout_width="wrap_content"
   android:layout_height="45dp"
   android:layout_gravity="bottom|end"
   android:adjustViewBounds="true"
   android:padding="5dp"
   android:scaleType="fitCenter"
   android:src="@drawable/ic_for_sale_outline"
   tools:src="@drawable/ic_for_sale_outline"/>
  1. Adicione o atributo android:visibility à vista da imagem mars_property_type. Use uma expressão de vinculação para testar o tipo de propriedade e atribua a visibilidade a View.GONE (para um aluguel) ou View.VISIBLE (para uma compra).
 android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"

Até agora você somente viu expressões de vinculação em layouts que usam variáveis ​​individuais definidas no elemento <data>. Expressões de vinculação são extremamente poderosas e permitem que você faça operações como testes e cálculos matemáticos inteiramente dentro do seu layout XML. Nesse caso, você usa o operador ternário (?:) para realizar um teste (este objeto é um aluguel?). Você fornece um resultado para verdadeiro (oculta o ícone de cifrão com View.GONE) e outro para falso (mostre esse ícone com View.VISIBLE).

O novo arquivo grid_view_item.xml completo é mostrado abaixo:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools">
   <data>
       <import type="android.view.View"/>
       <variable
           name="property"
           type="com.example.android.marsrealestate.network.MarsProperty" />
   </data>
   <FrameLayout
       android:layout_width="match_parent"
       android:layout_height="170dp">

       <ImageView
           android:id="@+id/mars_image"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"
           android:padding="2dp"
           app:imageUrl="@{property.imgSrcUrl}"
           tools:src="@tools:sample/backgrounds/scenic"/>

       <ImageView
           android:id="@+id/mars_property_type"
           android:layout_width="wrap_content"
           android:layout_height="45dp"
           android:layout_gravity="bottom|end"
           android:adjustViewBounds="true"
           android:padding="5dp"
           android:scaleType="fitCenter"
           android:src="@drawable/ic_for_sale_outline"
           android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"
           tools:src="@drawable/ic_for_sale_outline"/>
   </FrameLayout>
</layout>
  1. Compile e execute o aplicativo e observe que as propriedades que não são alugadas possuem o ícone de cifrão.

Atualmente, seu aplicativo exibe todas as propriedades de Marte na grade de visão geral. Se um usuário estivesse comprando um imóvel para alugar em Marte, seria útil ter os ícones para indicar quais dos imóveis disponíveis estão à venda, mas ainda há muitos imóveis para percorrer na página. Nesta tarefa, você adiciona um menu de opções ao fragmento de visão geral que permite ao usuário mostrar apenas aluguéis, apenas propriedades à venda ou mostrar todos.

Uma maneira de realizar essa tarefa é testar o tipo de cada MarsProperty na grade de visão geral e exibir apenas as propriedades correspondentes. O serviço da web Mars real, entretanto, tem um parâmetro de consulta ou opção (chamado filter) que permite que você obtenha apenas propriedades do tipo rent ou tipo buy. Você pode usar esta consulta de filtro com o URL do serviço da web realestate em um navegador como este:

https://android-kotlin-fun-mars-server.appspot.com/realestate?filter=buy

Nesta tarefa, você modifica a classe MarsApiService para adicionar uma opção de consulta à solicitação de serviço da web com Retrofit. Em seguida, você conecta o menu de opções para baixar novamente todos os dados de propriedade de Marte usando essa opção de consulta. Como a resposta que você obtém do serviço da web contém apenas as propriedades nas quais você está interessado, você não precisa alterar a lógica de exibição da vista para a grade de visão geral.

Etapa 1: Atualize o serviço Mars API

Para alterar a solicitação, você precisa revisitar a classe MarsApiService que você implementou no primeiro tutorial desta série. Você modifica a classe para fornecer uma API de filtragem.

  1. Abra network/MarsApiService.kt. Logo abaixo das importações, crie um enum chamado MarsApiFilter para definir constantes que correspondem aos valores de consulta que o serviço da web espera.
enum class MarsApiFilter(val value: String) {
   SHOW_RENT("rent"),
   SHOW_BUY("buy"),
   SHOW_ALL("all") }
  1. Modifique o método getProperties() para obter a entrada de string para a consulta de filtro e anote essa entrada com @Query("filter"), conforme mostrado abaixo.

    Importe retrofit2.http.Query quando solicitado.

    A anotação @Query diz ao método getProperties() (e, portanto, o Retrofit) para fazer a solicitação de serviço da web com a opção de filtro. Cada vez que getProperties() é chamado, o URL de solicitação inclui a parte ?filter=type, que direciona o serviço da web para responder com resultados que correspondam a essa consulta.
suspend fun getProperties(@Query("filter") type: String): List<MarsProperty>  

Etapa 2: Atualize o modelo de visão geral

Você solicita dados do MarsApiService no método getMarsRealEstateProperties() em OverviewViewModel. Agora você precisa atualizar essa solicitação para obter o argumento do filtro.

  1. Abra overview/OverviewViewModel.kt. Você verá erros no Android Studio devido às alterações feitas na etapa anterior. Adicione MarsApiFilter (o enum dos valores de filtro possíveis) como um parâmetro para a chamada getMarsRealEstateProperties().

    Importe com.example.android.marsrealestate.network.MarsApiFilter quando solicitado.
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {
  1. Modifique a chamada para getProperties() no serviço Retrofit para passar essa consulta de filtro como uma string.
 _properties.value = MarsApi.retrofitService.getProperties(filter.value)
  1. No bloco init {}, passe MarsApiFilter.SHOW_ALL como um argumento para getMarsRealEstateProperties(), para mostrar todas as propriedades quando o aplicativo for carregado pela primeira vez.
init {
   getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}
  1. No final da classe, adicione um método updateFilter() que recebe um argumento MarsApiFilter e chama getMarsRealEstateProperties() com esse argumento.
fun updateFilter(filter: MarsApiFilter) {
   getMarsRealEstateProperties(filter)
}

Etapa 3: Conecte o fragmento ao menu de opções

A última etapa é conectar o menu flutuante ao fragmento para chamar updateFilter() no modelo de vistas quando o usuário escolher uma opção de menu.

  1. Abra res/menu/overflow_menu.xml. O aplicativo MarsRealEstate tem um menu flutuante existente que fornece as três opções disponíveis: Mostrando todas as propriedades, mostra apenas os aluguéis e mostrar apenas as propriedades para venda.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <item
       android:id="@+id/show_all_menu"
       android:title="@string/show_all" />
   <item
       android:id="@+id/show_rent_menu"
       android:title="@string/show_rent" />
   <item
       android:id="@+id/show_buy_menu"
       android:title="@string/show_buy" />
</menu>
  1. Abra overview/OverviewFragment.kt. No final da aula, implemente o método onOptionsItemSelected() para tratar com as seleções de itens de menu.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
} 
  1. Em onOptionsItemSelected(), chame o método updateFilter() no modelo de vistas com o filtro apropriado. Use um bloco Kotlin when {} para alternar entre as opções. Use MarsApiFilter.SHOW_ALL para o valor de filtro padrão. Retorne true, pois você manipulou o item de menu. Importe MarsApiFilter (com.example.android.marsrealestate.network.MarsApiFilter) quando solicitado. O método onOptionsItemSelected() completo é mostrado abaixo.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
   viewModel.updateFilter(
           when (item.itemId) {
               R.id.show_rent_menu -> MarsApiFilter.SHOW_RENT
               R.id.show_buy_menu -> MarsApiFilter.SHOW_BUY
               else -> MarsApiFilter.SHOW_ALL
           }
   )
   return true
}
  1. Compile e execute o aplicativo. O aplicativo inicia a primeira grade de visão geral com todos os tipos de propriedades e as propriedades à venda marcadas com o ícone de dólar.
  2. Escolha Rent no menu de opções. As propriedades são recarregadas e nenhuma delas aparece com o ícone de dólar. (Somente propriedades para locação são mostradas). Você pode ter que esperar alguns momentos para que a exibição seja atualizada para mostrar apenas as propriedades filtradas.
  3. Escolha Buy no menu de opções. As propriedades são recarregadas novamente e todas aparecem com o ícone de dólar. (Apenas propriedades para venda são mostradas).

Agora você tem uma grade de rolagem de ícones para as propriedades de Marte, mas é hora de obter mais detalhes. Nesta tarefa, você adiciona um fragmento de detalhe para exibir os detalhes de uma propriedade específica. O fragmento de detalhes mostrará uma imagem maior, o preço e o tipo de propriedade - seja para aluguel ou venda.

Este fragmento é iniciado quando o usuário toca em uma imagem na grade de visão geral. Para fazer isso, você precisa adicionar um ouvinte onClick aos itens da grade RecyclerView e, a seguir, navegar até o novo fragmento. Você navega acionando uma alteração LiveData no ViewModel, como fez ao longo dessas lições. Você também usa o plug-in Safe Args do componente Navegação para passar as informações selecionadas da MarsProperty do fragmento de visão geral para o fragmento de detalhe.

Etapa 1: Crie o modelo de vistas de detalhes e atualizar o layout de detalhes

Semelhante ao processo usado para o modelo de visão geral e fragmentos, agora você precisa implementar o modelo de vistas e os arquivos de layout para o fragmento de detalhe.

  1. Abra detail/DetailViewModel.kt. Assim como os arquivos Kotlin relacionados à rede estão contidos na pasta network e os arquivos de visão geral na overview, a pasta detail contém os arquivos associados aos detalhes da vista. Observe que a classe DetailViewModel (vazia agora) recebe uma marsProperty como parâmetro no construtor.
class DetailViewModel( marsProperty: MarsProperty,
                     app: Application) : AndroidViewModel(app) {
}
  1. Dentro da definição da classe, adicione LiveData para a propriedade de Marte selecionada, para expor essas informações à vista de detalhes. Siga o padrão usual de criação de um MutableLiveData para conter a própria MarsProperty e, em seguida, exponha uma propriedade LiveData pública imutável.

    Importe androidx.lifecycle.LiveData e importar androidx.lifecycle.MutableLiveData quando solicitado.
private val _selectedProperty = MutableLiveData<MarsProperty>()
val selectedProperty: LiveData<MarsProperty>
   get() = _selectedProperty
  1. Crie um bloco init {} e defina o valor da propriedade Marte selecionada com o objeto MarsProperty do construtor.
    init {
        _selectedProperty.value = marsProperty
    }
  1. Abra res/layout/fragment_detail.xml e observe-o na vista do projeto.

    Este é o arquivo de layout para o fragmento de detalhe. Ele contém um ImageView para a foto grande, um TextView para o tipo de propriedade (aluguel ou venda) e um TextView para o preço. Observe que o layout de restrição é empacotado com um ScrollView, portanto, ele rolará automaticamente se a vista ficar muito grande para a exibição, por exemplo, quando o usuário visualiza no modo paisagem.
  2. Vá para a guia Text do layout. No topo do layout, pouco antes do elemento <ScrollView>, adicione um elemento <data> para associar o modelo de vistas de detalhes ao layout.
<data>
   <variable
       name="viewModel"
       type="com.example.android.marsrealestate.detail.DetailViewModel" />
</data>
  1. Adicione o atributo app:imageUrl ao elemento ImageView. Defina-o como imgSrcUrl a partir da propriedade selecionada do modelo de vista.

    O adaptador de vinculação que carrega uma imagem usando o Glide será usado automaticamente aqui também, pois esse adaptador observa todos os atributos app:imageUrl.
 app:imageUrl="@{viewModel.selectedProperty.imgSrcUrl}"

Etapa 2: Defina a navegação no modelo de visão geral

Quando o usuário toca em uma foto no modelo de visão geral, ele deve acionar a navegação para um fragmento que mostra detalhes sobre o item clicado.

  1. Abra overview/OverviewViewModel.kt. Adicione uma propriedade _navigateToSelectedProperty MutableLiveData e exponha-a com um LiveData imutável.

    Quando este LiveData muda para não nulo, a navegação é acionada. (Em breve, você adicionará o código para observar essa variável e acionar a navegação).
private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
val navigateToSelectedProperty: LiveData<MarsProperty>
   get() = _navigateToSelectedProperty
  1. No final da classe, adicione um método displayPropertyDetails() que define _navigateToSelectedProperty para a propriedade de Marte selecionada.
fun displayPropertyDetails(marsProperty: MarsProperty) {
   _navigateToSelectedProperty.value = marsProperty
}
  1. Adicione um método displayPropertyDetailsComplete() que anula o valor de _navigateToSelectedProperty. Você precisa disso para marcar o estado de navegação para concluir e para evitar que a navegação seja acionada novamente quando o usuário retornar da vista de detalhes.
fun displayPropertyDetailsComplete() {
   _navigateToSelectedProperty.value = null
}

Etapa 3: Configure os ouvintes de clique no adaptador de grade e no fragmento

  1. Abra overview/PhotoGridAdapter.kt. No final da classe, crie uma classe OnClickListener personalizada que recebe um lambda com um parâmetro marsProperty. Dentro da classe, defina uma função onClick() que é definida para o parâmetro lambda.
class OnClickListener(val clickListener: (marsProperty:MarsProperty) -> Unit) {
     fun onClick(marsProperty:MarsProperty) = clickListener(marsProperty)
}
  1. Role para cima até a definição de classe para o PhotoGridAdapter e adicione uma propriedade OnClickListener privada ao construtor.
class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
       ListAdapter<MarsProperty,              
           PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
  1. Torne uma foto clicável adicionando o onClickListener ao item de grade no método onBindviewHolder(). Defina o ouvinte de clique entre as chamadas para getItem() and bind().
override fun onBindViewHolder(holder: MarsPropertyViewHolder, position: Int) {
   val marsProperty = getItem(position)
   holder.itemView.setOnClickListener {
       onClickListener.onClick(marsProperty)
   }
   holder.bind(marsProperty)
}
  1. Abra overview/OverviewFragment.kt. No método onCreateView(), substitua a linha que inicializa a propriedade binding.photosGrid.adapter pela linha mostrada abaixo.

    Este código adiciona o objeto PhotoGridAdapter.onClickListener ao construtor PhotoGridAdapter e chama viewModel.displayPropertyDetails() com o -em objeto MarsProperty. Isso aciona o LiveData no modelo de vistas para a navegação.
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
   viewModel.displayPropertyDetails(it)
})

Etapa 4: Modifique o grafo de navegação e torne MarsProperty parcelável

Quando um usuário toca em uma foto na grade de visão geral, o aplicativo deve navegar até o fragmento de detalhes e passar pelos detalhes da propriedade de Marte selecionada para que a exibição de detalhes possa exibir essas informações.

Agora você tem um ouvinte de clique do PhotoGridAdapter para controlar o toque e uma maneira de acionar a navegação a partir do modelo de vista. Mas você ainda não tem um objeto MarsProperty sendo passado para o fragmento de detalhe. Para isso você usa Safe Args do componente de navegação.

  1. Abra res/navigation/nav_graph.xml. Clique na guia Text para visualizar o código XML do grafo de navegação.
  2. Dentro do elemento <fragment> para o fragmento de detalhe, adicione o elemento <argument> mostrado abaixo. Este argumento, denominado selectedProperty, tem o tipo MarsProperty.
<argument
   android:name="selectedProperty"
   app:argType="com.example.android.marsrealestate.network.MarsProperty"
   />
  1. Compile o aplicativo. A navegação fornece um erro, pois a MarsProperty não é parcelável. A interface Parcelable permite que os objetos sejam serializados, de forma que os dados dos objetos possam ser passados ​​entre fragmentos ou atividades. Nesse caso, para que os dados dentro do objeto MarsProperty sejam passados ​​para o fragmento de detalhe via Safe Args, MarsProperty deve implementar a interface Parcelable. A boa notícia é que o Kotlin oferece um atalho fácil para implementar essa interface.
  2. Abra network/MarsProperty.kt. Adicione a anotação @Parcelize à definição da classe.

    Importe kotlinx.android.parcel.Parcelize quando solicitado.

    A anotação @Parcelize usa as extensões Android Kotlin para implementar automaticamente os métodos na interface Parcelable para esta classe. Você não precisa fazer mais nada!
@Parcelize
data class MarsProperty (
  1. Altere a definição de classe de MarsProperty para estender Parcelable.

    Importe android.os.Parcelable quando solicitado.

    A definição da classe MarsProperty agora se parece com isto:
@Parcelize
data class MarsProperty (
       val id: String,
       @Json(name = "img_src") val imgSrcUrl: String,
       val type: String,
       val price: Double) : Parcelable {

Etapa 5: Conecte os fragmentos

Você ainda não está navegando - a navegação real acontece nos fragmentos. Nesta etapa, você adiciona os últimos bits para implementar a navegação entre a visão geral e os fragmentos de detalhes.

  1. Abra overview/OverviewFragment.kt. Em onCreateView(), abaixo das linhas que inicializam o adaptador de grade de fotos, adicione as linhas mostradas abaixo para observar navigatedToSelectedProperty no modelo de visão geral.

    Importe androidx.lifecycle.Observer e importar androidx.navigation.fragment.findNavController quando solicitado.

    O observador testa se MarsProperty—o it no lambda — não é nulo, e se for, obtém o controlador de navegação do fragmento com findNavController(). Chame displayPropertyDetailsComplete() para dizer ao modelo de vistas para redefinir o LiveData para o estado nulo, para que você não acione acidentalmente a navegação novamente quando o aplicativo retornar ao OverviewFragment.
viewModel.navigateToSelectedProperty.observe(this, Observer {
   if ( null != it ) {   
      this.findNavController().navigate(
              OverviewFragmentDirections.actionShowDetail(it))             
      viewModel.displayPropertyDetailsComplete()
   }
})
  1. Abra detail/DetailFragment.kt. Adicione esta linha logo abaixo, definindo a propriedade binding.lifecycleOwner no método onCreateView(). Esta linha obtém o objeto MarsProperty selecionado do Safe Args.

    Observe o uso do operador de asserção não nulo de Kotlin (!!). Se selectedProperty não estiver lá, algo terrível aconteceu e você realmente deseja que o código lance um ponteiro nulo. (No código de produção, você deve lidar com esse erro de alguma forma).
 val marsProperty = DetailFragmentArgs.fromBundle(arguments!!).selectedProperty
  1. Adicione esta linha a seguir, para obter uma nova DetailViewModelFactory. Você usará DetailViewModelFactory para obter uma instância de DetailViewModel. O aplicativo inicial inclui uma implementação de DetailViewModelFactory, então tudo que você precisa fazer aqui é inicializá-lo.
val viewModelFactory = DetailViewModelFactory(marsProperty, application)
  1. Finalmente, adicione esta linha para obter um DetailViewModel da fábrica e conectar todas as partes.
      binding.viewModel = ViewModelProvider(
                this, viewModelFactory).get(DetailViewModel::class.java)
  1. Compile e execute o aplicativo e toque em qualquer foto de propriedade de Marte. O fragmento de detalhe aparece para os detalhes dessa propriedade. Toque no botão Voltar para retornar à página de visão geral e observe que a tela de detalhes ainda é esparsa. Você termina de adicionar os dados de propriedade a essa página de detalhes na próxima tarefa.

No momento, a página de detalhes mostra apenas a mesma foto de Marte que você está acostumado a ver na página de visão geral. A classe MarsProperty também tem um tipo de propriedade (alugar ou comprar) e um preço de propriedade. A tela de detalhes deve incluir esses dois valores e seria útil se os imóveis para locação indicassem que o preço era por mês. Use as transformações LiveData no modelo de vistas para implementar ambas.

  1. Abra res/values/strings.xml. O código inicial inclui recursos de string, mostrados abaixo, para ajudá-lo a construir as strings para a vista de detalhes. Para o preço, você usará o recurso display_price_monthly_rental ou o recurso display_price, dependendo do tipo de propriedade.
<string name="type_rent">Rent</string>
<string name="type_sale">Sale</string>
<string name="display_type">For %s</string>
<string name="display_price_monthly_rental">$%,.0f/month</string>
<string name="display_price">$%,.0f</string>
  1. Abra detail/DetailViewModel.kt. Na parte inferior da classe, adicione o código mostrado abaixo.

    Importe androidx.lifecycle.Transformations se solicitado.

    Esta transformação testa se a propriedade selecionada é uma locação, utilizando o mesmo teste da primeira tarefa. Se a propriedade for alugada, a transformação escolhe a string apropriada dos recursos com um Kotlin when {} alternar. Ambas as strings precisam de um número no final, então você concatena o property.price depois.
val displayPropertyPrice = Transformations.map(selectedProperty) {
   app.applicationContext.getString(
           when (it.isRental) {
               true -> R.string.display_price_monthly_rental
               false -> R.string.display_price
           }, it.price)
}
  1. Importe a classe R gerada para obter acesso aos recursos de string no projeto.
import com.example.android.marsrealestate.R
  1. Após a transformação displayPropertyPrice, adicione o código mostrado abaixo. Essa transformação concatena vários recursos de string, com base no fato de o tipo de propriedade ser um aluguel.
val displayPropertyType = Transformations.map(selectedProperty) {
   app.applicationContext.getString(R.string.display_type,
           app.applicationContext.getString(
                   when (it.isRental) {
                       true -> R.string.type_rent
                       false -> R.string.type_sale
                   }))
}
  1. Abra res/layout/fragment_detail.xml. somente há mais uma tarefa a fazer, e isso é vincular as novas strings (que você criou com as transformações LiveData) à vista de detalhes. Para fazer isso, você define o valor do campo de texto para o texto do tipo de propriedade como viewModel.displayPropertyType, e o campo de texto para o texto do valor do preço como viewModel.displayPropertyPrice.
<TextView
   android:id="@+id/property_type_text"
...
android:text="@{viewModel.displayPropertyType}"
...
   tools:text="To Rent" />

<TextView
   android:id="@+id/price_value_text"
...
android:text="@{viewModel.displayPropertyPrice}"
...
   tools:text="$100,000" />
  1. Compile e execute o aplicativo. Agora todos os dados de propriedade aparecem na página de detalhes, bem formatados.

Projeto Android Studio: MarsRealEstateFinal

Expressões de vinculação

Opções de consulta de serviço da Web

Documentação para desenvolvimento em Android:

De outros:

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

O que a etiqueta <import> em um arquivo de layout XML faz?

▢ Inclua um arquivo de layout em outro.

▢ Incorpore o código Kotlin dentro do arquivo de layout.

▢ Fornece acesso a propriedades vinculadas a dados.

▢ Permite que você faça referência a classes e membros de classe em expressões de vinculação.

Pergunta 2

Como você adiciona uma opção de consulta a uma chamada de serviço da web REST no Retrofit?

▢ Anexe a consulta ao final do URL da solicitação.

▢ Adicione um parâmetro para a consulta à função que faz a solicitação e anote esse parâmetro com @Query.

▢ Use a classe Query para construir uma solicitação.

▢ Use o método addQuery() no construtor Retrofit.

Comece a próxima lição: 09.1: Repositório

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