Android Kotlin Hakkında Temel Bilgiler 08.3 İnternet verileriyle filtreleme ve ayrıntı görünümleri

Bu codelab, Android Kotlin Hakkında Temel Bilgiler kursunun bir parçasıdır. Bu kurstan en iyi şekilde yararlanmak için codelab'leri sırayla tamamlamanızı öneririz. Kursla ilgili tüm codelab'ler Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında listelenir.

Giriş

Bu dersin önceki codelab'lerinde, Mars'taki gayrimenkullerle ilgili verileri bir web hizmetinden nasıl alacağınızı ve bu verilerdeki resimleri yükleyip görüntülemek için ızgara düzenine sahip bir RecyclerView oluşturmayı öğrendiniz. Bu codelab'de, Mars mülklerini kiralık veya satılık olup olmamasına göre filtreleme özelliğini uygulayarak MarsRealEstate uygulamasını tamamlayacaksınız. Ayrıca, kullanıcı genel bakışta bir tesis fotoğrafına dokunduğunda tesisle ilgili ayrıntıların yer aldığı bir ayrıntı görünümü görmesi için ayrıntı görünümü de oluşturursunuz.

Bilmeniz gerekenler

  • Parçacık oluşturma ve kullanma
  • Parçalar arasında gezinme ve parçalar arasında veri aktarmak için Safe Args'ı (bir Gradle eklentisi) kullanma.
  • Görünüm modelleri, görünüm modeli fabrikaları, dönüşümler ve LiveData dahil olmak üzere mimari bileşenleri kullanma
  • Retrofit ve Moshi kitaplıklarını kullanarak REST web hizmetinden JSON kodlu verileri alma ve bu verileri Kotlin nesnelerine ayrıştırma.

Neler öğreneceksiniz?

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

Yapacaklarınız

  • Satılık Mars mülklerini (kiralık olanların aksine) dolar işareti simgesiyle işaretlemek için MarsRealEstate uygulamasını değiştirin.
  • Genel bakış sayfasındaki seçenekler menüsünü kullanarak Mars özelliklerini türe göre filtreleyen bir web hizmeti isteği oluşturun.
  • Bir Mars mülkü için ayrıntı parçası oluşturun, bu parçayı gezinme içeren genel bakış ızgarasına bağlayın ve mülk verilerini bu parçaya aktarın.

Bu codelab'de (ve ilgili codelab'lerde) MarsRealEstate adlı bir uygulamayla çalışacaksınız. Bu uygulama, Mars'ta satılık mülkleri gösterir. Bu uygulama, fiyat ve mülkün satılık veya kiralık olup olmadığı gibi ayrıntılar da dahil olmak üzere mülk verilerini almak ve görüntülemek için bir internet sunucusuna bağlanır. Her bir tesisi temsil eden görüntüler, NASA'nın Mars keşif araçları tarafından çekilen gerçek Mars fotoğraflarıdır. Önceki codelab'lerde, tüm tesis fotoğrafları için ızgara düzenine sahip bir RecyclerView oluşturmuştunuz:

Uygulamanın bu sürümünde, mülkün türüyle (kiralık veya satılık) çalışır ve satılık mülkleri işaretlemek için ızgara düzenine bir simge eklersiniz:

Uygulamanın seçenek menüsünü, ızgarayı yalnızca kiralık veya satılık mülkleri gösterecek şekilde filtrelemek için değiştirirsiniz:

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:

Şimdiye kadar Mars mülk verilerinin yalnızca mülk resminin URL'sini kullandınız. Ancak MarsProperty sınıfında tanımladığınız mülk verileri de kimlik, fiyat ve tür (kiralık veya satılık) içerir. Hatırlatmak için web hizmetinden aldığınız JSON verilerinin bir snippet'ini aşağıda bulabilirsiniz:

{
   "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, genel bakış sayfasındaki satılık mülklere dolar işareti resmi eklemek için Mars mülk türüyle çalışmaya başlayacaksınız.

1. adım: MarsProperty'yi 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 gelen ham JSON yanıtını tek tek MarsProperty veri nesnelerine ayrıştırmak için Moshi kitaplığını kullanmıştınız.

Bu adımda, bir mülkün kiralık olup olmadığını (yani türün "rent" veya "buy" dizesi olup olmadığını) belirtmek için MarsProperty sınıfına bazı mantıklar eklersiniz. Bu mantığı birden fazla yerde kullanacağınız için mantığı burada, veri sınıfında bulundurmak, kopyalamaktan daha iyidir.

  1. Son codelab'deki MarsRealEstate uygulamasını açın. (Uygulama yüklü değilse MarsRealEstateGrid'i indirebilirsiniz.)
  2. network/MarsProperty.kt adlı kişiyi aç. MarsProperty sınıf tanımına bir gövde ekleyin ve isRental için özel bir alıcı ekleyin. Bu alıcı, nesne "rent" türündeyse true değerini döndürür.
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

Şimdi, yalnızca satılık olan tesis resimlerinde dolar işareti çizilebilir öğesini göstermek için resim ızgarasının öğe düzenini güncelleyin:

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

  1. res/layout/grid_view_item.xml adlı kişiyi aç. Bu, RecyclerView için ızgara düzenindeki her bir hücrenin düzen dosyasıdır. Şu anda dosya yalnızca mülk resmi için <ImageView> öğesini içeriyor.
  2. <data> öğesinin içine View sınıfı için bir <import> öğesi ekleyin. Bir sınıfın bileşenlerini bir düzen dosyasındaki veri bağlama ifadesinde kullanmak istediğinizde içe aktarmaları kullanırsınız. 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. Dolar işaretiyle çizilebilen öğenin mülk resminin üzerine yerleştirilmesine izin vermek için tüm resim görünümünü FrameLayout ile çevreleyin.
<FrameLayout
   android:layout_width="match_parent"
   android:layout_height="170dp">
             <ImageView 
                    android:id="@+id/mars_image"
            ...
</FrameLayout>
  1. ImageView için yeni üst öğe FrameLayout'ü doldurmak üzere android:layout_height özelliğini match_parent olarak değiştirin.
android:layout_height="match_parent"
  1. FrameLayout içinde, ilk <ImageView> öğesinin hemen altına ikinci bir <ImageView> öğesi ekleyin. Aşağıda gösterilen tanımı kullanın. Bu resim, ızgara öğesinin sağ alt köşesinde, Mars resminin üzerinde görünür ve dolar işareti simgesi için res/drawable/ic_for_sale_outline.xml içinde tanımlanan çizilebilir öğeyi 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 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şkenlerin kullanıldığı düzenlerde bağlama ifadelerini görmüş olabilirsiniz. Bağlama ifadeleri son derece güçlüdür ve testler ile matematiksel hesaplamalar gibi işlemleri tamamen XML düzeninizde yapmanıza olanak tanır. Bu durumda, bir testi (Bu nesne kiralık mı?) gerçekleştirmek için üçlü operatörü (?:) kullanırsınız. Doğru için bir sonuç (dolar işareti simgesini View.GONE ile gizleyin), yanlış için ise başka bir sonuç (bu simgeyi View.VISIBLE ile gösterin) sağlarsınız.

Yeni tamamlanmış grid_view_item.xml dosyası aşağıda gösterilmektedir:

<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ülklerin dolar işareti simgesine sahip olduğunu unutmayın.

Uygulamanız şu anda genel bakış ızgarasında tüm Mars mülklerini gösteriyor. Bir kullanıcı Mars'ta kiralık mülk arıyorsa mevcut mülklerden hangilerinin satılık olduğunu gösteren simgeler faydalı olur ancak sayfada kaydırılması gereken çok sayıda mülk vardır. Bu görevde, genel bakış parçasına bir seçenekler menüsü ekleyerek kullanıcının yalnızca kiralık yerleri, yalnızca satılık yerleri veya tümünü göstermesini sağlayacaksınız.

Bu görevi yerine getirmenin bir yolu, genel bakış tablosundaki her MarsProperty için türü test etmek ve yalnızca eşleşen özellikleri göstermektir. Ancak gerçek Mars web hizmetinde, yalnızca rent türündeki veya buy türündeki özellikleri almanızı sağlayan bir sorgu parametresi ya da seçenek (filter olarak adlandırılır) vardır. Bu filtre sorgusunu, tarayıcıda realestate web hizmeti URL'siyle birlikte şu şekilde 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, bu sorgu seçeneğini kullanarak tüm Mars mülk verilerini yeniden indirmek için seçenekler menüsünü bağlarsınız. Web hizmetinden aldığınız yanıt yalnızca ilgilendiğiniz özellikleri içerdiğinden, genel bakış ızgarası için görünüm görüntüleme mantığını hiç 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ı tekrar ziyaret etmeniz gerekir. Filtreleme API'si sağlamak için sınıfı değiştirirsiniz.

  1. network/MarsApiService.kt adlı kişiyi aç. İçe aktarma işlemlerinin hemen altında, web hizmetinin beklediği sorgu değerleriyle eşleşen sabitleri tanımlamak için enum adlı bir MarsApiFilter oluşturun.
enum class MarsApiFilter(val value: String) {
   SHOW_RENT("rent"),
   SHOW_BUY("buy"),
   SHOW_ALL("all") }
  1. Filtre sorgusu için dize girişi alacak şekilde getProperties() yöntemini değiştirin ve bu girişi aşağıda gösterildiği gibi @Query("filter") ile açıklama ekleyin.

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

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

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

OverviewViewModel içinde getMarsRealEstateProperties() yönteminde MarsApiService'dan veri isteğinde bulunursunuz. Şimdi bu isteği filtre bağımsız değişkenini alacak şekilde güncellemeniz gerekiyor.

  1. overview/OverviewViewModel.kt adlı kişiyi aç. Önceki adımda yaptığınız değişiklikler nedeniyle Android Studio'da hatalar görürsünüz. MarsApiFilter (olası filtre değerlerinin numaralandırılmış türü) öğesini getMarsRealEstateProperties() çağrısına parametre olarak ekleyin. İstendiğinde

    İçe aktar'ı com.example.android.marsrealestate.network.MarsApiFilter tıklayın.
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {
  1. Bu filtre sorgusunu dize olarak iletmek için Retrofit hizmetindeki getProperties() çağrısını değiştirin.
var getPropertiesDeferred = MarsApi.retrofitService.getProperties(filter.value)
  1. Uygulama ilk yüklendiğinde tüm özellikleri göstermek için init {} bloğunda MarsApiFilter.SHOW_ALL öğesini getMarsRealEstateProperties() için bağımsız değişken olarak iletin.
init {
   getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}
  1. Sınıfın sonuna, updateFilter() bağımsız değişkenini alan ve getMarsRealEstateProperties() işlevini bu bağımsız değişkenle çağıran bir MarsApiFilter 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ının bir menü seçeneğini belirlediğinde görünüm modelinde updateFilter() işlevini çağırmak için taşma menüsünü parçaya bağlamaktır.

  1. res/menu/overflow_menu.xml adlı kişiyi aç. MarsRealEstate uygulamasında, mevcut bir taşma menüsü vardır. Bu menüde üç seçenek sunulur: tüm mülkleri gösterme, yalnızca kiralık mülkleri gösterme ve yalnızca 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 adlı kişiyi aç. Dersin sonunda, menü öğesi seçimlerini işlemek için onOptionsItemSelected() yöntemini uygulayın.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
} 
  1. onOptionsItemSelected() içinde, görünüm modelinde updateFilter() yöntemini uygun filtreyle çağırın. Seçenekler arasında geçiş yapmak için Kotlin when {} bloğunu kullanın. Varsayılan filtre değeri için MarsApiFilter.SHOW_ALL değerini kullanın. Menü öğesini işlediğiniz için true değerini döndürün. İstendiğinde MarsApiFilter (com.example.android.marsrealestate.network.MarsApiFilter) dosyasını içe aktarın. Tam onOptionsItemSelected() yöntemi aşağıda gösterilmektedir.
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ürlerini içeren ilk genel bakış ızgarasını başlatır ve satılık mülkler dolar simgesiyle işaretlenir.
  2. Seçenekler menüsünden Kirala'yı seçin. Mülkler yeniden yüklenir ve hiçbiri dolar simgesiyle görünmez. (Yalnızca kiralık mülkler gösterilir.) Yalnızca filtrelenmiş mülkleri göstermek için ekranın yenilenmesi birkaç dakika sürebilir.
  3. Seçenekler menüsünden Satın al'ı seçin. Mülkler yeniden yüklenir ve tümü dolar simgesiyle görünür. (Yalnızca satılık mülkler gösterilir.)

Artık Mars tesislerinin simgelerini içeren kaydırılabilir bir ızgaranız var ancak daha fazla ayrıntı edinme zamanı geldi. Bu görevde, belirli bir mülkün ayrıntılarını göstermek için ayrıntı parçası ekleyeceksiniz. Ayrıntı parçası daha büyük bir resim, fiyat ve mülk türünü (kiralık veya satılık) gösterir.

Bu parça, kullanıcı genel bakış ızgarasındaki bir resme dokunduğunda başlatılır. Bunu yapmak için onClick öğelerine RecyclerView dinleyici eklemeniz ve ardından yeni parçaya gitmeniz gerekir. Bu derslerde yaptığınız gibi, ViewModel içinde LiveData değişikliği tetikleyerek gezinirsiniz. Ayrıca, seçilen MarsProperty bilgilerini genel bakış parçasından ayrıntı parçasına iletmek için Navigation bileşeninin Safe 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 sürece benzer şekilde, artık ayrıntı parçası için görünüm modeli ve düzen dosyalarını uygulamanız gerekiyor.

  1. detail/DetailViewModel.kt adlı kişiyi aç. Ağla ilgili Kotlin dosyaları network klasöründe, genel bakış dosyaları ise overview klasöründe yer alır. Benzer şekilde, detail klasöründe de ayrıntı görünümüyle ilişkili dosyalar bulunur. DetailViewModel sınıfının (şu anda boş) oluşturucuda parametre olarak marsProperty aldığını unutmayın.
class DetailViewModel( marsProperty: MarsProperty,
                     app: Application) : AndroidViewModel(app) {
}
  1. Sınıf tanımının içinde, seçilen Mars mülkü için LiveData ekleyerek bu bilgileri ayrıntı görünümünde gösterin. MarsProperty öğesini tutacak bir MutableLiveData oluşturma ve ardından değişmez bir genel LiveData özelliği kullanıma sunma şeklindeki normal kalıbı izleyin. İstendiğinde

    içe aktarın androidx.lifecycle.LiveData ve androidx.lifecycle.MutableLiveData.
private val _selectedProperty = MutableLiveData<MarsProperty>()
val selectedProperty: LiveData<MarsProperty>
   get() = _selectedProperty
  1. Bir init {} bloğu oluşturun ve oluşturucudaki MarsProperty nesnesiyle seçilen Mars mülkünün değerini ayarlayın.
    init {
        _selectedProperty.value = marsProperty
    }
  1. res/layout/fragment_detail.xml dosyasını açıp tasarım görünümünde inceleyin.

    Bu, ayrıntı parçası için düzen dosyasıdır. Büyük fotoğraf için ImageView, tesis türü (kiralık veya satılık) için TextView ve fiyat için TextView içerir. Kısıtlama düzeninin ScrollView ile sarmalandığını unutmayın. Bu nedenle, görünüm ekrana sığmayacak kadar büyüdüğünde (örneğin, kullanıcı görünümü yatay modda görüntülediğinde) otomatik olarak kaydırılır.
  2. Düzen için Metin sekmesine gidin. Düzenin en üstünde, <ScrollView> öğesinden hemen önce, 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ünüm modelinin seçili özelliğinden imgSrcUrl olarak ayarlayın.

    Glide kullanarak bir resmi yükleyen bağlama bağdaştırıcısı, 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ış modelinde bir fotoğrafa dokunduğunda, tıklanan öğeyle ilgili ayrıntıları gösteren bir parçaya yönlendirme tetiklenmelidir.

  1. overview/OverviewViewModel.kt adlı kişiyi aç. _navigateToSelectedProperty MutableLiveData özelliği ekleyin ve bunu değişmez bir LiveData ile kullanıma sunun.

    Bu LiveData değeri null olmayan bir değere değiştiğinde gezinme tetiklenir. (Yakında bu değişkeni gözlemlemek ve gezinmeyi tetiklemek için kodu ekleyeceksiniz.)
private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
val navigateToSelectedProperty: LiveData<MarsProperty>
   get() = _navigateToSelectedProperty
  1. Sınıfın sonunda, _navigateToSelectedProperty değerini seçilen Mars mülküne ayarlayan bir displayPropertyDetails() yöntemi ekleyin.
fun displayPropertyDetails(marsProperty: MarsProperty) {
   _navigateToSelectedProperty.value = marsProperty
}
  1. _navigateToSelectedProperty değerini boş yapan bir displayPropertyDetailsComplete() yöntemi ekleyin. Bu, gezinme durumunu tamamlandı olarak işaretlemek ve kullanıcı ayrıntı görünümünden döndüğünde gezinmenin tekrar tetiklenmesini önlemek için gereklidir.
fun displayPropertyDetailsComplete() {
   _navigateToSelectedProperty.value = null
}

3. adım: Izgara bağdaştırıcısında ve parçada tıklama dinleyicilerini ayarlayın

  1. overview/PhotoGridAdapter.kt adlı kişiyi aç. Sınıfın sonunda, marsProperty parametreli bir 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 sınıfının sınıf tanımına gidin ve oluşturucuya özel bir OnClickListener özelliği ekleyin.
class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
       ListAdapter<MarsProperty,              
           PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
  1. onClickListener yönteminde onBindviewHolder() öğesine onClickListener ekleyerek fotoğrafı tıklanabilir hale getirin. Tıklama işleyicisini getItem() and bind() çağrıları arasında 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 adlı kişiyi aç. 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şturucusuna ekler ve iletilen MarsProperty nesnesiyle viewModel.displayPropertyDetails() işlevini çağırır. Bu işlem, gezinme için görünüm modelinde LiveData öğesini tetikler.
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
   viewModel.displayPropertyDetails(it)
})

4. adım: Gezinme grafiğini değiştirin ve MarsProperty'yi paketlenebilir hale getirin

Kullanıcı, genel bakış ızgarasında bir fotoğrafa dokunduğunda uygulama, ayrıntı parçasına gitmeli ve seçilen Mars mülkünün ayrıntılarını aktarmalıdır. Böylece ayrıntı görünümünde bu bilgiler gösterilebilir.

Şu anda dokunma işlemini işlemek için PhotoGridAdapter öğesinden bir tıklama işleyiciye ve görünüm modelinden gezinmeyi tetikleme yöntemine sahipsiniz. Ancak henüz ayrıntı parçasına iletilen bir MarsProperty nesneniz yok. Bunun için gezinme bileşenindeki Safe Args'ı kullanırsınız.

  1. res/navigation/nav_graph.xml adlı kişiyi aç. Gezinme grafiğinin XML kodunu görüntülemek 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şkenin türü MarsProperty'dir.
<argument
   android:name="selectedProperty"
   app:argType="com.example.android.marsrealestate.network.MarsProperty"
   />
  1. Uygulamayı derleyin. MarsProperty, parcelable olmadığı için gezinme sırasında hata alırsınız. Parcelable arayüzü, nesnelerin serileştirilmesini sağlar. Böylece nesnelerin verileri parçalar veya etkinlikler arasında aktarılabilir. Bu durumda, MarsProperty nesnesinin içindeki verilerin Safe Args aracılığıyla ayrıntı parçasına aktarılması için MarsProperty, Parcelable arayüzünü uygulamalıdır. Kotlin, bu arayüzü uygulamak için kolay bir kısayol sunar.
  2. network/MarsProperty.kt adlı kişiyi aç. 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ündeki yöntemleri otomatik olarak uygulamak üzere Kotlin Android uzantılarını kullanır. Başka bir işlem yapmanız gerekmez.
@Parcelize
data class MarsProperty (
  1. MarsProperty sınıf tanımını, Parcelable'ı genişletecek şekilde 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 adlı kişiyi aç. onCreateView() içinde, fotoğraf ızgarası bağdaştırıcısını başlatan satırların altına, genel bakış görünümü modelinden navigatedToSelectedProperty öğesini gözlemlemek için aşağıda gösterilen satırları ekleyin. İstendiğinde

    içe aktarın androidx.lifecycle.Observer ve androidx.navigation.fragment.findNavController.

    Gözlemci, lambda'daki MarsPropertyit değerinin null olup olmadığını test eder. Null değilse findNavController() ile parçadan gezinme denetleyicisini alır. Görünüm modeline LiveData değerini null durumuna sıfırlamasını söylemek için displayPropertyDetailsComplete() işlevini çağırın. Böylece uygulama OverviewFragment öğesine döndüğünde gezinmeyi yanlışlıkla tekrar tetiklemezsiniz.
viewModel.navigateToSelectedProperty.observe(this, Observer {
   if ( null != it ) {   
      this.findNavController().navigate(
              OverviewFragmentDirections.actionShowDetail(it))             
      viewModel.displayPropertyDetailsComplete()
   }
})
  1. detail/DetailFragment.kt adlı kişiyi aç. Bu satırı, onCreateView() yöntemindeki setLifecycleOwner() çağrısının hemen altına ekleyin. Bu satır, Safe Args'dan seçilen MarsProperty nesneyi alır.

    Kotlin'in null olmayan onaylama operatörünün (!!) kullanıldığına dikkat edin. selectedProperty yoksa korkunç bir şey olmuştur ve kodun aslında null işaretçi oluşturmasını istersiniz. (Üretim kodunda bu hatayı bir şekilde ele almanız gerekir.)
 val marsProperty = DetailFragmentArgs.fromBundle(arguments!!).selectedProperty
  1. Yeni bir DetailViewModelFactory almak için bu satırı ekleyin. DetailViewModel örneğini almak için DetailViewModelFactory kullanırsınız. Başlangıç uygulamasında DetailViewModelFactory'nın bir uygulaması bulunur. Bu nedenle, burada yapmanız gereken tek şey onu başlatmaktır.
val viewModelFactory = DetailViewModelFactory(marsProperty, application)
  1. Son olarak, fabrikadan DetailViewModel almak ve tüm parçaları bağlamak için bu çizgiyi ekleyin.
      binding.viewModel = ViewModelProviders.of(
                this, viewModelFactory).get(DetailViewModel::class.java)
  1. Uygulamayı derleyip çalıştırın ve herhangi bir Mars mülkünün fotoğrafına dokunun. Söz konusu mülkün ayrıntıları için ayrıntı parçası gösterilir. Genel bakış sayfasına dönmek için geri düğmesine dokunun. Ayrıntı ekranının hâlâ biraz seyrek olduğunu göreceksiniz. Mülk verilerini bu ayrıntılar sayfasına ekleme işlemini sonraki görevde tamamlarsınız.

Şu anda ayrıntılar sayfasında yalnızca genel bakış sayfasında görmeye alıştığınız Mars fotoğrafı gösteriliyor. MarsProperty sınıfında ayrıca bir mülk türü (kiralama veya satın alma) ve mülk fiyatı bulunur. Ayrıntılar ekranında bu değerlerin her ikisi de yer almalıdır. Kiralık mülklerin, fiyatın aylık değer olduğunu belirtmesi faydalı olur. Bu iki şeyi uygulamak için görünüm modelinde LiveData dönüşümlerini kullanırsınız.

  1. res/values/strings.xml adlı kişiyi aç. Başlangıç kodu, ayrıntı görünümü için dizeler oluşturmanıza yardımcı olmak üzere 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 kaynağını 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 adlı kişiyi aç. Sınıfın en altına aşağıdaki kodu ekleyin. İstenirse

    İçe aktar'ı androidx.lifecycle.Transformations tıklayın.

    Bu dönüşüm, ilk görevdeki testle aynı testi kullanarak seçilen mülkün kiralık olup olmadığını test eder. Mülk kiralıksa dönüştürme, Kotlin when {} anahtarıyla kaynaklardan uygun dizeyi seçer. Bu dizelerin her ikisinin de sonunda bir sayı olması gerekir. Bu nedenle, property.price sonrasında birleştirme yaparsınız.
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üşümünden sonra aşağıda gösterilen kodu ekleyin. Bu dönüşüm, mülk türünün kiralık olup olmamasına bağlı olarak birden fazla dize kaynağını birleştirir.
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 adlı kişiyi aç. Yapılacak tek bir işlem kaldı: LiveData dönüşümleriyle oluşturduğunuz yeni dizeleri ayrıntı görünümüne bağlamak. Bunu yapmak için özellik türü metni için metin alanının değerini viewModel.displayPropertyType, fiyat değeri metni için metin alanının değerini ise 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ı derleyip çalıştırın. Artık tüm mülk verileri, ayrıntılar sayfasında düzgün bir şekilde biçimlendirilmiş olarak görünüyor.

Android Studio projesi: MarsRealEstateFinal

Bağlama ifadeleri

  • Bağlı veriler üzerinde matematik veya koşullu testler gibi basit programatik işlemler gerçekleştirmek için XML düzen dosyalarında bağlama ifadelerini kullanın.
  • Düzen dosyanızdaki sınıflara referans vermek için <import> etiketi içindeki <data> etiketini kullanın.

Web hizmeti sorgu seçenekleri

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

Udacity kursu:

Android geliştirici belgeleri:

Diğer:

Bu bölümde, bir eğitmenin yönettiği kurs kapsamında bu codelab'i tamamlayan öğrenciler için olası ödevler listelenmektedir. Eğitmen, aşağıdakileri yapmalıdır:

  • Gerekirse ödev atayın.
  • Öğrencilere ev ödevi ödevlerini nasıl göndereceklerini bildirin.
  • Ödevlere not verin.

Eğitmenler bu önerileri istedikleri kadar kullanabilir ve uygun olduğunu düşündükleri diğer ödevleri verebilirler.

Bu codelab'i kendi başınıza tamamlıyorsanız bilginizi test etmek için bu ödevleri kullanabilirsiniz.

Bu soruları yanıtlayın

1. Soru

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

▢ Bir düzen dosyasını diğerine dahil etme.

▢ Kotlin kodunu düzen dosyasına yerleştirin.

▢ Verilere bağlı mülklere erişim izni verin.

▢ Bağlama ifadelerinde sınıflara ve sınıf üyelerine referans vermenizi sağlar.

2. Soru

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

▢ Sorguyu istek URL'sinin sonuna ekleyin.

▢ İsteği yapan işleve sorgu için bir parametre ekleyin ve bu parametreyi @Query ile açıklama olarak 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: Depo

Bu kurstaki diğer codelab'lerin bağlantılarını Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında bulabilirsiniz.