Android Kotlin Fundamentals 08.3 İnternet verileriyle filtreleme ve ayrıntı görünümleri

Bu codelab, Android Kotlin Temelleri kursuna dahildir. Codelab'ler üzerinden sırayla çalışıyorsanız bu kurstan en iyi şekilde yararlanabilirsiniz. Tüm kurs codelab'leri Android Kotlin Fundamentals codelabs açılış sayfasında listelenmektedir.

Giriş

Bu dersin önceki codelab'lerinde, bir web hizmetinden Mars'ta gayrimenkul verileri almayı ve bu verilerdeki resimleri yükleyip görüntülemek için tablo düzeniyle nasıl RecyclerView oluşturacağınızı öğrendiniz. Bu codelab'de, Mars mülklerini kiralanabilen ya da satın alınabilen web sitelerine göre filtreleme özelliğini uygulayarak MarsRealEstate uygulamasını tamamladınız. Ayrıca, kullanıcı genel bakış içindeki bir mülk fotoğrafına dokunursa mülkle ilgili ayrıntıları içeren bir ayrıntılı görünüm göreceği için ayrıntılı görünüm de oluşturursunuz.

Bilmeniz gerekenler

  • Parça oluşturma ve kullanma.
  • Parçalar arasında gezinme ve parçalar arasında veri iletmek için Güvenli Args (Gradle eklentisi) kullanma.
  • Görünüm modelleri, görünüm modeli fabrikaları, dönüşümler ve LiveData dahil olmak üzere mimari bileşenlerin nasıl kullanılacağı.
  • Bir REST web hizmetinden JSON kodlu verileri alma ve bu verileri Retrofit ve Moshi kitaplıklarıyla Kotlin nesnelerine ayrıştırma.

Neler öğreneceksiniz?

  • Düzen dosyalarınızda karmaşık bağlama ifadeleri kullanma.
  • Sorgu seçenekleriyle web hizmetine Retrofit istekleri gönderme.

Ne yaparsınız?

  • Satılık Mars mülklerini (kiralık olanlar yerine) dolar işareti simgesiyle işaretlemek için MarsRealEstate uygulamasını değiştirin.
  • Mars mülklerini türe göre filtreleyen bir web hizmeti isteği oluşturmak için genel bakış sayfasındaki seçenekler menüsünü kullanın.
  • Mars mülkü için bir ayrıntı parçası oluşturun, bu parçayı gezinmeyle genel bakış tablosuna bağlayın ve mülk verilerini bu parçaya geçirin.

Bu codelab'de (ve ilgili codelab'lerde) MarsRealEstate adında, Mars'ta satılık mülkleri gösteren bir uygulamayla çalışıyorsunuz. Bu uygulama, fiyat bilgisi ve tesisin satılık veya kiralık olup olmadığı gibi ayrıntılar dahil olmak üzere tesis verilerini almak ve görüntülemek için bir internet sunucusuna bağlanır. Her mülkü temsil eden resimler, Mars'ın Mars gezginlerinden çekilen Mars'ın gerçek fotoğraflarıdır. Önceki codelab'lerde, tüm mülk fotoğrafları için ızgara düzenine sahip bir RecyclerView oluşturdunuz:

Uygulamanın bu sürümünde mülkün türüyle (kiralama ve satın alma) birlikte çalışır ve satılık mülkleri işaretlemek için tablo düzenine bir simge eklersiniz:

Uygulamanın seçenek menüsünü değiştirerek ızgarayı yalnızca kiralanabilen veya satılık tesisleri gösterecek şekilde filtreleyebilirsiniz:

Son olarak, tek bir mülk için ayrıntı görünümü oluşturur ve genel bakış ızgarasındaki simgeleri gezinme özelliğiyle bu ayrıntı parçasına bağlarsınız:

Şu ana kadar, Mars mülkü verilerinin tek parçası, mülk resminin URL'siydi. Ancak, MarsProperty sınıfında tanımladığınız mülk verileri de bir kimlik, fiyat ve tür (kiralık veya satılık) içerir. Hafızanızı tazelemek için web hizmetinden aldığınız JSON verilerinin snippet'i aşağıda verilmiştir:

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

Bu görevde satıştaki genel bakış sayfasındaki mülklere dolar işareti eklemek için Mars mülkü türüyle çalışmaya başlarsınız.

1. Adım: MarsProperty'i türü içerecek şekilde güncelleyin

MarsProperty sınıfı, web hizmeti tarafından sağlanan her mülkün veri yapısını tanımlar. Önceki bir codelab'de, Mars web hizmetinden ham JSON yanıtını bağımsız MarsProperty veri nesnelerine ayrıştırmak için Moshi kitaplığını kullanıyordunuz.

Bu adımda, MarsProperty sınıfına bir mülkün kiralık olup olmadığını (yani türün "rent" veya "buy" dizesi olup olmadığını) belirtmek için bazı mantık eklersiniz. Bu mantığı birden fazla yerde kullanırsınız. Bu nedenle, bu mantığı veri sınıfında çoğaltmak yerine burada kullanmanız daha iyi olur.

  1. Son codelab'den MarsRealEstate uygulamasını açın. (Uygulamanız yoksa MarsRealEstateEnlem'i indirebilirsiniz.)
  2. network/MarsProperty.kt'yi açın. MarsProperty Sınıf tanımına bir gövde ekleyin ve nesne "rent" türündeyse isRental döndüren true için özel bir alıcı ekleyin.
data class MarsProperty(
       val id: String,
       @Json(name = "img_src") val imgSrcUrl: String,
       val type: String,
       val price: Double)  {
   val isRental
       get() = type == "rent"
}

2. Adım: Izgara öğesi düzenini güncelleyin

Artık resimler ızgarasına ait öğe düzenini güncelleyerek yalnızca satılan satılık resimlerde bir dolar işareti çizebilirsiniz:

Veri bağlama ifadeleriyle bu testi tamamen ızgara öğelerinin XML düzeninde yapabilirsiniz.

  1. res/layout/grid_view_item.xml'yi açın. Bu, RecyclerView tablosunun ızgara düzenindeki her bir hücrenin düzen dosyasıdır. Şu anda dosya, mülk resmi için yalnızca <ImageView> öğesini içeriyor.
  2. <data> öğesinin içine View sınıfı için bir <import> öğesi ekleyin. İçe aktarma özelliğini, bir düzen dosyasındaki veri bağlama ifadesi içinde bir sınıfın bileşenlerini kullanmak istediğinizde kullanabilirsiniz. Bu durumda, View.GONE ve View.VISIBLE sabitlerini kullanacağınız için View sınıfına erişmeniz gerekir.
<import type="android.view.View"/>
  1. Resim görünümünün tamamını bir FrameLayout resmiyle çevreleyin. Böylece dolar işaretinin çizim resminin mülk resminin üzerine yığılmasına izin verilir.
<FrameLayout
   android:layout_width="match_parent"
   android:layout_height="170dp">
             <ImageView 
                    android:id="@+id/mars_image"
            ...
</FrameLayout>
  1. ImageView öğesinde android:layout_height üst öğesini yeni FrameLayout alanını doldurmak için match_parent olarak değiştirin.
android:layout_height="match_parent"
  1. İlk öğenin hemen altına, FrameLayout içine ikinci bir <ImageView> öğesi ekleyin. Aşağıda gösterilen tanımı kullanın. Bu resim, Mars resminin üst kısmında, ızgara öğesinin sağ alt köşesinde görünür ve dolar işareti simgesi için res/drawable/ic_for_sale_outline.xml öğesinde çizilebilir olanı kullanır.
<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. android:visibility özelliğini mars_property_type resim görünümüne ekleyin. Mülk türünü test etmek için bir bağlama ifadesi kullanın ve görünürlüğü View.GONE (kiralama için) veya View.VISIBLE (satın alma için) olarak atayın.
 android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"

Şu ana kadar, yalnızca <data> öğesinde tanımlanan bağımsız değişkenleri kullanan düzenlerde bağlayıcı ifadeler gördünüz. Bağlama ifadeleri son derece güçlü olup testleriniz ve matematik hesaplamaları gibi işlemleri XML düzeninizde gerçekleştirmenizi sağlar. Bu durumda, test gerçekleştirmek için üçlü operatörü (?:) kullanırsınız (bu nesne bir kiralık mı?). Doğru için bir sonuç sağlarsınız (View.GONE ile dolar işareti simgesini gizleyin) ve yanlış için başka bir sonuç sağlayın (bu simgeyi View.VISIBLE ile gösterin).

Yeni grid_view_item.xml dosyasının tamamı aşağıda gösterilmiştir:

<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. Uygulamayı derleyip çalıştırın. Kiralık olmayan mülklerde dolar işareti simgesi olduğunu unutmayın.

Şu anda uygulamanız, genel bakış tablosunda tüm Mars mülklerini gösteriyor. Bir kullanıcı Mars'ta kiralık mülk alışverişi yapıyorsa, mevcut gayrimenkullerden hangilerinin satışta olduğunu belirten simgeler kullanmak yararlı olacaktır, ancak sayfada gezinilecek çok sayıda mülk olmalıdır. Bu görevde, genel bakış parçasına kullanıcının yalnızca kiralık mülkleri, yalnızca satılık mülkleri veya tümünü göstermesini sağlayan bir seçenekler menüsü eklersiniz.

Bu görevi gerçekleştirmenin bir yolu, genel bakış tablosunda her bir MarsProperty için türü test etmek ve yalnızca eşleşen özellikleri görüntülemektir. Ancak asıl Mars web hizmeti, yalnızca rent veya buy türündeki mülkleri elde etmenizi sağlayan bir sorgu parametresine veya seçeneğine (filter olarak adlandırılır) sahiptir. Bu filtre sorgusunu aşağıdaki gibi bir tarayıcıda realestate web hizmeti URL'si ile kullanabilirsiniz:

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

Bu görevde, Retrofit ile web hizmeti isteğine bir sorgu seçeneği eklemek için MarsApiService sınıfını değiştirirsiniz. Ardından, ilgili sorgu seçeneğini kullanarak tüm Mars mülkü verilerini yeniden indirmek için seçenekler menüsünü bağlayabilirsiniz. Web hizmetinden aldığınız yanıt yalnızca ilgilendiğiniz mülkleri içerdiğinden genel bakış ızgarası için görüntüleme mantığını değiştirmeniz gerekmez.

1. Adım: Mars API hizmetini güncelleyin

İsteği değiştirmek için bu serideki ilk codelab'de uyguladığınız MarsApiService sınıfını yeniden ziyaret etmeniz gerekir. Sınıfı, bir filtreleme API'si sağlayacak şekilde değiştirirsiniz.

  1. network/MarsApiService.kt'yi açın. İçe aktarmaların hemen altında, web hizmetinin beklediği sorgu değerleriyle eşleşen sabit değerler tanımlamak için MarsApiFilter adında bir enum oluşturun.
enum class MarsApiFilter(val value: String) {
   SHOW_RENT("rent"),
   SHOW_BUY("buy"),
   SHOW_ALL("all") }
  1. Filtre sorgusu için dize girişini almak üzere getProperties() yöntemini değiştirin ve bu girişi aşağıda gösterildiği gibi @Query("filter") ile ekleyin.

    İstendiğinde retrofit2.http.Query içe aktarın.

    @Query ek açıklaması, getProperties() yöntemine (ve dolayısıyla Retrofit'e) filtre seçeneğiyle web hizmeti isteği yapmasını söyler. getProperties() her çağrıldığında, istek URL'si ?filter=type bölümünü içerir. Bu bölüm, web hizmetini bu sorguyla eşleşen sonuçlarla yanıt vermeye yönlendirir.
fun getProperties(@Query("filter") type: String):  

2. Adım: Genel bakış görünümü modelini güncelleyin

OverviewViewModel için getMarsRealEstateProperties() yöntemindeki MarsApiService kaynağından veri istiyorsunuz. Şimdi, filtre bağımsız değişkenini almak için bu isteği güncellemeniz gerekiyor.

  1. overview/OverviewViewModel.kt'yi açın. Önceki adımda yaptığınız değişiklikler nedeniyle Android Studio'da hatalar göreceksiniz. getMarsRealEstateProperties() çağrısına parametre olarak MarsApiFilter (olası filtre değerlerinin toplamı) ekleyin.

    İstendiğinde com.example.android.marsrealestate.network.MarsApiFilter içe aktarın.
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {
  1. Söz konusu filtre sorgusunu dize olarak iletmek için Retrofit hizmetinde çağrıyı getProperties() olarak değiştirin.
var getPropertiesDeferred = MarsApi.retrofitService.getProperties(filter.value)
  1. Uygulama ilk yüklendiğinde tüm özellikleri göstermek için init {} blokunda MarsApiFilter.SHOW_ALL öğesini getMarsRealEstateProperties() bağımsız değişkenine geçirin.
init {
   getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}
  1. Sınıfın sonunda, bir MarsApiFilter bağımsız değişkenini alan ve bu bağımsız değişkenle birlikte getMarsRealEstateProperties()'yi çağıran bir updateFilter() yöntemi ekleyin.
fun updateFilter(filter: MarsApiFilter) {
   getMarsRealEstateProperties(filter)
}

3. Adım: Parçayı seçenekler menüsüne bağlayın

Son adım, kullanıcı bir menü seçeneği belirlediğinde görünüm modelinde updateFilter() öğesini çağırmak için taşma menüsünü parçaya bağlamaktır.

  1. res/menu/overflow_menu.xml'yi açın. MarsRealEstate uygulamasında mevcut üç seçeneği sağlayan bir taşma menüsü var: Tüm mülkleri gösterme, yalnızca kiralık yerleri gösterme ve sadece satılık mülkleri gösterme.
<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. overview/OverviewFragment.kt'yi açın. Dersin sonunda menü öğesi seçimlerini yönetmek için onOptionsItemSelected() yöntemini uygulayın.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
} 
  1. onOptionsItemSelected() için uygun modeli kullanarak görünüm modelindeki updateFilter() yöntemini çağırın. Seçenekler arasında geçiş yapmak için Kotlin when {} bloğu kullanın. Varsayılan filtre değeri için MarsApiFilter.SHOW_ALL değerini kullanın. Menü öğesini işlediğiniz için true ürününü iade edin. İstendiğinde MarsApiFilter (com.example.android.marsrealestate.network.MarsApiFilter) içe aktarın. onOptionsItemSelected() yönteminin tamamı aşağıda gösterilmiştir.
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. Uygulamayı derleyip çalıştırın. Uygulama, tüm mülk türleri ve dolar simgesiyle işaretlenmiş satış özellikleri ile ilk genel bakış ızgarasını başlatır.
  2. Seçenekler menüsünden Kirala'yı seçin. Özellikler yeniden yüklenir ve hiçbiri dolar simgesiyle görünmez. (Yalnızca kiralık mülkler gösterilir.) Yalnızca filtrelenen özelliklerin gösterilmesi amacıyla ekranın yenilenmesi için birkaç dakika beklemeniz gerekebilir.
  3. Seçenekler menüsünden Satın al'ı seçin. Özellikler yeniden yüklenir ve hepsi dolar simgesiyle görünür. (Yalnızca satılık mülkler gösterilir.)

Artık Mars mülkleri için kayan bir simge ızgaranıza sahipsiniz, ancak şimdi daha ayrıntılı bilginin zamanı geldi. Bu görevde belirli bir özelliğin ayrıntılarını görüntülemek için bir ayrıntı parçası eklersiniz. Ayrıntı parçası daha büyük bir resim, fiyat ve kiralık ya da satılık mülk türünü gösterir.

Bu parça, kullanıcı genel bakış tablosundaki bir resme dokunduğunda başlatılır. Bunu yapmak için RecyclerView ızgara öğelerine bir onClick işleyici eklemeniz ve ardından yeni parçaya gitmeniz gerekir. Bu derslerde yaptığınız gibi ViewModel konumunda LiveData değişikliği tetikleyerek geziniyorsunuz. Seçili MarsProperty bilgilerini genel bakış parçasından ayrıntı parçasına iletmek için Gezinme bileşeninin Güvenli Args eklentisini de kullanırsınız.

1. Adım: Ayrıntı görünümü modelini oluşturun ve ayrıntı düzenini güncelleyin

Genel bakış görünümü modeli ve parçaları için kullandığınız yönteme benzer şekilde, şimdi ayrıntılı parça için görünüm modelini ve düzen dosyalarını uygulamanız gerekir.

  1. detail/DetailViewModel.kt'yi açın. Ağla ilgili Kotlin dosyalarının, overview klasöründeki network klasöründe ve genel bakış dosyalarında bulunması gibi, detail klasörü de ayrıntılı görünümle ilişkilendirilmiş dosyaları içerir. DetailViewModel sınıfının (şu anda boş) oluşturucuda marsProperty olarak parametre aldığına dikkat edin.
class DetailViewModel( marsProperty: MarsProperty,
                     app: Application) : AndroidViewModel(app) {
}
  1. Ayrıntılı açıklamayı göstermek için, sınıf tanımının içinde, seçili Mars mülküne ait LiveData öğesini ekleyin. MarsProperty öğesini tutmak için normal bir MutableLiveData oluşturma modeli uygulayın, ardından sabit bir genel LiveData özelliğini gösterin.

    İstendiğinde androidx.lifecycle.LiveData içe aktarın ve androidx.lifecycle.MutableLiveData içe aktarın.
private val _selectedProperty = MutableLiveData<MarsProperty>()
val selectedProperty: LiveData<MarsProperty>
   get() = _selectedProperty
  1. init {} bloku oluşturun ve oluşturucudan alınan MarsProperty nesnesiyle seçili Mars mülkünün değerini ayarlayın.
    init {
        _selectedProperty.value = marsProperty
    }
  1. res/layout/fragment_detail.xml uygulamasını açın ve tasarım görünümünde inceleyin.

    Bu, ayrıntı parçasının düzen dosyasıdır. Büyük fotoğraf için bir ImageView, tesis türü (kiralama veya satış) için bir TextView ve fiyat için bir TextView içerir. Kısıtlama düzeninin bir ScrollView ile sarmalandığına dikkat edin. Bu nedenle, görünüm ekran için çok büyük olduğunda (örneğin, kullanıcı yatay modda görüntülediğinde) otomatik olarak kaydırılır.
  2. Düzen için Metin sekmesine gidin. Düzenin üst kısmında, <ScrollView> öğesinin hemen önüne, ayrıntı görünümü modelini düzenle ilişkilendirmek için bir <data> öğesi ekleyin.
<data>
   <variable
       name="viewModel"
       type="com.example.android.marsrealestate.detail.DetailViewModel" />
</data>
  1. app:imageUrl özelliğini ImageView öğesine ekleyin. Görüntü modelinin seçili mülkünden imgSrcUrl değerine ayarlayın.

    Kaydırma özelliğiyle resim yükleyen bağlayıcı adaptörü de tüm app:imageUrl özelliklerini izlediği için burada da otomatik olarak kullanılır.
 app:imageUrl="@{viewModel.selectedProperty.imgSrcUrl}"

2. Adım: Genel bakış görünümü modelinde gezinmeyi tanımlayın

Kullanıcı, genel bakış modelindeki bir fotoğrafa dokunduğunda, tıklanan öğeyle ilgili ayrıntıların gösterildiği bir parçanın gezinmesini tetiklemelidir.

  1. overview/OverviewViewModel.kt'yi açın. Bir _navigateToSelectedProperty MutableLiveData özelliği ekleyin ve bunu sabit bir LiveData ile gösterin.

    Bu LiveData boş değer olarak değiştiğinde gezinme tetiklenir. (Yakında bu değişkeni gözlemleyip gezinmeyi tetiklemek için kodu ekleyeceksiniz.)
private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
val navigateToSelectedProperty: LiveData<MarsProperty>
   get() = _navigateToSelectedProperty
  1. Sınıfın sonuna, seçili Mars mülküne _navigateToSelectedProperty değerini ayarlayan bir displayPropertyDetails() yöntemi ekleyin.
fun displayPropertyDetails(marsProperty: MarsProperty) {
   _navigateToSelectedProperty.value = marsProperty
}
  1. _navigateToSelectedProperty değerini geçersiz kılan bir displayPropertyDetailsComplete() yöntemi ekleyin. Bunu, gezinme durumunu tamamlamak için işaretlemeniz ve kullanıcı ayrıntı görünümünden çıktığında gezinmenin tekrar tetiklenmesini sağlamanız gerekir.
fun displayPropertyDetailsComplete() {
   _navigateToSelectedProperty.value = null
}

3. Adım: Tıklama dinleyicileri, ızgara adaptöründe ve parçada ayarlayın

  1. overview/PhotoGridAdapter.kt'yi açın. Sınıfın sonunda, marsProperty parametresiyle lambda alan özel bir OnClickListener sınıfı oluşturun. Sınıfın içinde, lambda parametresine ayarlanmış bir onClick() işlevi tanımlayın.
class OnClickListener(val clickListener: (marsProperty:MarsProperty) -> Unit) {
     fun onClick(marsProperty:MarsProperty) = clickListener(marsProperty)
}
  1. PhotoGridAdapter öğesinin sınıf tanımına ilerleyin ve oluşturucuya gizli bir OnClickListener özelliği ekleyin.
class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
       ListAdapter<MarsProperty,              
           PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
  1. onBindviewHolder() yönteminde ızgara öğesine onClickListener ekleyerek bir fotoğrafı tıklanabilir hale getirin. getItem() and bind() çağrısı arasında tıklama işleyiciyi tanımlayın.
override fun onBindViewHolder(holder: MarsPropertyViewHolder, position: Int) {
   val marsProperty = getItem(position)
   holder.itemView.setOnClickListener {
       onClickListener.onClick(marsProperty)
   }
   holder.bind(marsProperty)
}
  1. overview/OverviewFragment.kt'yi açın. onCreateView() yönteminde, binding.photosGrid.adapter özelliğini başlatan satırı aşağıda gösterilen satırla değiştirin.

    Bu kod, PhotoGridAdapter.onClickListener nesnesini PhotoGridAdapter oluşturucuya ekler ve iletilen MarsProperty nesnesiyle viewModel.displayPropertyDetails() öğesini çağırır. Bu işlem, gezinme için görünüm modelindeki LiveData öğesini tetikler.
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
   viewModel.displayPropertyDetails(it)
})

4. Adım: Gezinme grafiğini değiştirin ve MarsProperty'i ayrıştırılabilir hale getirin

Kullanıcı genel bakış tablosundaki bir fotoğrafa dokunduğunda, uygulama ayrıntı parçasına gidip seçili Mars mülkünün ayrıntılarını iletmelidir. Böylece, ayrıntı görünümü söz konusu bilgileri görüntüleyebilir.

Şu anda, dokunma işlemini gerçekleştirmek için PhotoGridAdapter tıklama dinleyiciniz ve görüntüleme modelinde gezinmeyi tetiklemenin bir yolu vardır. Ancak henüz ayrıntı parçasına iletilmiş bir MarsProperty nesneniz yok. Bunun için gezinme bileşenindeki Güvenli Argıları kullanırsınız.

  1. res/navigation/nav_graph.xml'yi açın. Gezinme grafiğine ait XML kodunu görmek için Metin sekmesini tıklayın.
  2. Ayrıntı parçası için <fragment> öğesinin içine aşağıda gösterilen <argument> öğesini ekleyin. selectedProperty adlı bu bağımsız değişken MarsProperty türündedir.
<argument
   android:name="selectedProperty"
   app:argType="com.example.android.marsrealestate.network.MarsProperty"
   />
  1. Uygulamayı derleyin. Gezinme özelliği, MarsProperty ayrıştırılabileceği için size bir hata veriyor. Parcelable arayüzü, nesnelerin serileştirilebilmesini sağlar. Böylece nesneler, parçalar veya etkinlikler arasında iletilebilir. Bu durumda, MarsProperty nesnesinin içindeki verilerin Güvenli Kayışlar aracılığıyla ayrıntı parçasına iletilmesi için MarsProperty öğesinin Parcelable arayüzünü uygulaması gerekir. Ancak, Kotlin bu arayüzün uygulanması için kolay bir kısayol sunuyor.
  2. network/MarsProperty.kt'yi açın. Sınıf tanımına @Parcelize ek açıklamasını ekleyin.

    İstendiğinde kotlinx.android.parcel.Parcelize öğesini içe aktarın.

    @Parcelize ek açıklaması, bu sınıf için Parcelable arayüzünde yöntemleri otomatik olarak uygulamak üzere Kotlin Android uzantılarını kullanıyor. Bu durumda herhangi bir şey yapmanız gerekmez.
@Parcelize
data class MarsProperty (
  1. Parcelable öğesinin kapsamını genişletmek için MarsProperty sınıf tanımını değiştirin.

    İstendiğinde android.os.Parcelable içe aktarın.

    MarsProperty sınıf tanımı artık şu şekilde görünüyor:
@Parcelize
data class MarsProperty (
       val id: String,
       @Json(name = "img_src") val imgSrcUrl: String,
       val type: String,
       val price: Double) : Parcelable {

5. Adım: Parçaları bağlayın

Hâlâ gezinmiyorsunuz. Gerçek gezinme, parçalarda gerçekleşir. Bu adımda, genel bakış ve ayrıntı parçaları arasında gezinmeyi uygulamak için son bitleri eklersiniz.

  1. overview/OverviewFragment.kt'yi açın. onCreateView() içinde, fotoğraf ızgara bağdaştırıcısını başlatan çizgilerin altına, genel bakış görünümü modelinden navigatedToSelectedProperty gözlemlemek için aşağıda gösterilen satırları ekleyin.

    İstendiğinde androidx.lifecycle.Observer içe aktarın ve androidx.navigation.fragment.findNavController içe aktarın.

    Gözlemci, lambdadaki it adlı MarsProperty öğesinin boş olup olmadığını test eder ve böyle bir durumda gezinme denetleyicisini findNavController() içeren parçadan alır. displayPropertyDetailsComplete() modelinde, görünüm modelinin LiveData değerini boş duruma sıfırlamasını söylemek için çağrı yapın. Böylece, uygulama OverviewFragment öğesine geri döndüğünde yanlışlıkla navigasyonu tetiklemez.
viewModel.navigateToSelectedProperty.observe(this, Observer {
   if ( null != it ) {   
      this.findNavController().navigate(
              OverviewFragmentDirections.actionShowDetail(it))             
      viewModel.displayPropertyDetailsComplete()
   }
})
  1. detail/DetailFragment.kt'yi açın. Bu satırı, onCreateView() yönteminde setLifecycleOwner() çağrısının hemen altına ekleyin. Bu satır, seçili MarsProperty nesnesini Güvenli bağımsız değişkenlerden alıyor.

    Kotlin's boş olmayan onaylama operatörü (!!) kullanıldığına dikkat edin. selectedProperty yoksa ürkütücü bir durum oluştu ve kodun boş işaretçiye ulaşmasını istersiniz. (Üretim kodunda bu hatayı bir şekilde ele almanız gerekir.)
 val marsProperty = DetailFragmentArgs.fromBundle(arguments!!).selectedProperty
  1. Yeni DetailViewModelFactory alabilmek için bu satırı ekleyin. DetailViewModel öğesinin bir örneğini almak için DetailViewModelFactory makrosunu kullanacaksınız. Başlangıç uygulaması, DetailViewModelFactory uygulamasını içerdiğinden, burada tek yapmanız gereken uygulamayı başlatmaktır.
val viewModelFactory = DetailViewModelFactory(marsProperty, application)
  1. Son olarak, bu satırı fabrikadan DetailViewModel almak ve tüm parçaları bağlamak için ekleyin.
      binding.viewModel = ViewModelProviders.of(
                this, viewModelFactory).get(DetailViewModel::class.java)
  1. Uygulamayı oluşturun ve çalıştırın ve herhangi bir Mars mülkü fotoğrafına dokunun. Söz konusu mülkün ayrıntıları için ayrıntı parçası görünür. Genel bakış sayfasına dönmek için Geri düğmesine dokunun ve ayrıntı ekranının hâlâ biraz seyrek olduğunu fark edin. Bir sonraki görevde özellik verilerini ayrıntılar sayfasına eklemeyi tamamlarsınız.

Şu anda ayrıntılar sayfasında yalnızca alışkın olduğunuz Mars fotoğrafı genel bakış sayfasında gösterilir. Ayrıca MarsProperty sınıfının bir tesis türü (kiralama veya satın alma) ve tesis fiyatı vardır. Ayrıntılar ekranında her iki değer de bulunmalıdır. Kiralık mülkler, fiyatın aylık değer olduğunu gösteriyorsa faydalı olur. Bu öğelerin her ikisini de uygulamak için görünüm modelinde LiveData dönüşümlerini kullanırsınız.

  1. res/values/strings.xml'yi açın. Başlangıç kodu, ayrıntılı görünüm için dizeler oluşturmanıza yardımcı olacak, aşağıda gösterilen dize kaynaklarını içerir. Fiyat için mülk türüne bağlı olarak display_price_monthly_rental veya display_price kaynağını kullanırsınız.
<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. detail/DetailViewModel.kt'yi açın. Sınıfın en altına, aşağıda gösterilen kodu ekleyin.

    İstenirse androidx.lifecycle.Transformations içe aktarın.

    Bu dönüştürme işleminde, ilk görevdeki aynı test kullanılarak, seçilen mülkün kiralık olup olmadığı test edilir. Mülk bir kiralıkysa dönüşüm, Kotlin when {} anahtarı bulunan kaynaklardan uygun dizeyi seçer. Bu dizelerin her ikisinin de sonunda bir sayı olması gerekir, dolayısıyla property.price öğesini daha sonra birleştirirsiniz.
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. Projedeki dize kaynaklarına erişmek için, oluşturulan R sınıfını içe aktarın.
import com.example.android.marsrealestate.R
  1. displayPropertyPrice dönüştürme işleminden sonra aşağıda gösterilen kodu ekleyin. Bu dönüştürme işleminde, mülk türünün kiralama olup olmadığına bağlı olarak birden fazla dize kaynağı birleştirilir.
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. res/layout/fragment_detail.xml'yi açın. Yalnızca bir adım daha var ve yeni dizeleri (LiveData dönüşümleriyle oluşturduğunuz) ayrıntı görünümüne bağlamak gerekir. Bunun için tesis türü metin için metin alanının değerini viewModel.displayPropertyType, fiyat değeri metninin metin alanını viewModel.displayPropertyPrice olarak ayarlarsınız.
<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. Uygulamayı oluşturun ve çalıştırın. Tüm mülk verileri artık ayrıntılar sayfasında düzgün bir şekilde biçimlendirilmiş olarak görünür.

Android Studio projesi: MarsRealEstateFinal

İfadeleri bağlama

  • Kısıtlanmış verilerdeki matematiksel veya koşullu testler gibi basit programatik işlemleri gerçekleştirmek için XML düzen dosyalarında bağlayıcı ifadeleri kullanın.
  • Düzen dosyanızdaki sınıflara referans vermek için <data> etiketinin içindeki <import> etiketini kullanın.

Web hizmeti sorgu seçenekleri

  • Web hizmetlerine yapılan istekler isteğe bağlı parametreleri içerebilir.
  • İstekte sorgu parametrelerini belirtmek için Retrofit'teki @Query ek açıklamasını kullanın.

Udacity kursu:

Android geliştirici dokümanları:

Diğer:

Bu bölümde, bir eğitmen tarafından sunulan kurs kapsamında bu codelab üzerinden çalışan öğrenciler için olası ev ödevi ödevleri listelenmektedir. Öğretmenin şunları yapması gerekir:

  • Gerekirse ev ödevini atayın.
  • Öğrencilere ev ödevlerinin nasıl gönderileceğini bildirin.
  • Ev ödevlerine not verin.

Öğretmenler bu önerileri istedikleri kadar kullanabilir veya uygun görebilir ve uygun olan diğer ev ödevlerini atayabilirler.

Bu codelab'de kendiniz çalışıyorsanız, bilginizi test etmek için bu ödevlerden yararlanabilirsiniz.

Bu soruları yanıtlayın

1. Soru

Bir XML düzeni dosyasındaki <import> etiketi ne işe yarar?

▢ ile bir düzen dosyası eklemek.

▢ Kotlin kodunu düzen dosyasının içine yerleştirin.

▢ Verilere bağlı mülklere erişim sağlar.

▢ Bağlayıcı ifadeler kullanarak sınıflara ve sınıf üyelerine referans vermenizi sağlar.

2. Soru

Retrofit'te REST web hizmeti çağrısına nasıl sorgu seçeneği eklenir?

▢ Sorgu URL'sinin sonuna ekleyin.

▢ İsteği yapan işleve sorgu için bir parametre ekleyip @Query ile bu parametreye not ekleyin.

▢ İstek oluşturmak için Query sınıfını kullanın.

▢ Retrofit oluşturucuda addQuery() yöntemini kullanın.

Sonraki derse başlayın: 9.1: Repository

Bu kurstaki diğer codelab'lerin bağlantılarına ulaşmak için Android Kotlin Fundamentals codelabs açılış sayfasına göz atın.