Android Kotlin Fundamentals 08.2: İnternetten resim yükleme ve görüntüleme

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ş

Önceki codelab'de, web hizmetinden veri almayı ve yanıtı veri nesnesine ayrıştırmayı öğrendiniz. Bu codelab'de, web URL'sinden fotoğraf yüklemek ve görüntülemek için bu bilgilere dayanarak hareket edeceksiniz. Ayrıca, RecyclerView oluşturmayı ve genel bakış sayfasında bir tablo ızgarasını görüntülemek için de kullanabilirsiniz.

Bilmeniz gerekenler

  • Parça oluşturma ve 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ğı.
  • REST web hizmetinden JSON alma ve Retrofit ile Moshi kitaplıklarını kullanarak bu verileri Kotlin nesnelerine ayrıştırma.
  • RecyclerView ile tablo düzeni oluşturma.
  • Adapter, ViewHolder ve DiffUtil nasıl işler?

Neler öğreneceksiniz?

  • Web URL'sinden bir resim yüklemek ve görüntülemek için Kaydırma kitaplığını kullanma.
  • Resim ızgarası görüntülemek için RecyclerView ve ızgara adaptörü nasıl kullanılır?
  • Resimler indirilirken ve görüntülenirken olası hataları ele alma.

Ne yaparsınız?

  • MarsRealEstate uygulamasında değişiklik yaparak Mars mülkü verilerinden resim URL'sini alın ve bu görseli yükleyip görüntülemek için Kaydır'ı kullanın.
  • Uygulamaya bir yükleme animasyonu ve hata simgesi ekleyin.
  • Mars mülkü resim ızgarasını görüntülemek için RecyclerView kullanın.
  • RecyclerView cihazına durum ve hata işleme özelliklerini ekleyin.

Bu codelab'de (ve ilgili codelab'lerde) MarsRealEstate adında, Mars'ta satılık mülkleri gösteren bir uygulamayla çalışıyorsunuz. Uygulama, fiyat bilgisi ve mülkün 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.

Bu codelab'de oluşturduğunuz uygulamanın sürümü, bir tablo ızgarası görüntüleyen genel bakış sayfası ile doldurulur. Resimler, uygulamanızın Mars emlak web hizmetinden aldığı mülk verilerinin bir parçasıdır. Uygulamanız, resimleri yüklemek ve görüntülemek için Kaydırarak kitaplığı ve resimler için tablo düzeni oluşturmak üzere bir RecyclerView kullanır. Uygulamanız ayrıca ağ hatalarını zarif bir şekilde işleyebilir.

Web URL'sinden bir fotoğraf görüntülemek basit bir işlem gibi görünse de fotoğrafı iyi bir şekilde işlemesi için epey mühendislik yapıldı. Resmin indirilmiş olması, arabelleğe alınması ve sıkıştırılmış biçiminden Android'in kullanabileceği bir resme dönüştürülmesi gerekir. Resim; bellek içi bir önbellek, depolamaya dayalı önbellek veya her ikisi için de önbelleğe alınmalıdır. Kullanıcı arayüzünün yanıt vermeye devam etmesi için tüm bu işlemleri düşük öncelikli arka plan mesaj dizilerinde gerçekleştirmeniz gerekir. Ayrıca, en iyi ağ ve CPU performansı için aynı anda birden fazla görüntü getirmek ve kodu çözmek isteyebilirsiniz. Ağdan resimleri etkili bir şekilde nasıl yükleyeceğinizi öğrenmek tek başına bir codelab olabilir.

Neyse ki, resimlerinizi indirmek, arabelleğe almak, çözümlemek ve önbelleğe almak için Glide adlı, topluluk tarafından geliştirilmiş bir kitaplığı kullanabilirsiniz. Kaydırarak tüm bunları sıfırdan yapmak zorunda kalacağınızdan çok daha az iş yaparsınız.

Kaydırarak iki temel koşul gereklidir:

  • Yüklemek ve göstermek istediğiniz resmin URL'si.
  • Bu resmi görüntülemek için bir ImageView nesnesi.

Bu görevde emlak web hizmetinden tek bir resim görüntülemek için Kaydırarak kullanmayı öğreneceksiniz. Web hizmetinin döndürdüğü mülkler listesinde ilk Mars mülkünü temsil eden resmi gösterirsiniz. İşte önceki ve sonraki ekran görüntüleri:

1. Adım: Kaydırmalı bağımlılık ekleyin

  1. Son codelab'den MarsRealEstate uygulamasını açın. (Uygulamanız yoksa MarsRealEstateNetwork'ü indirebilirsiniz.)
  2. Ne işe yaradığını görmek için uygulamayı çalıştırın. (Mars'ta mevcut olabilecek farazi bir mülkün metin ayrıntılarını görüntüler.)
  3. build.gradle (Modül: uygulama) bölümünü açın.
  4. dependencies bölümünde, Kaydırarak kitaplık için bu satırı ekleyin:
implementation "com.github.bumptech.glide:glide:$version_glide"


Sürüm numarasının, proje Gradle dosyasında ayrı olarak tanımlandığını unutmayın.

  1. Projeyi yeni bağımlılıkla yeniden oluşturmak için Sync Now'ı (Şimdi Senkronize Et) tıklayın.

2. Adım: Görünüm modelini güncelleyin

Sonra, OverviewViewModel sınıfını tek bir Mars mülkünün canlı verilerini içerecek şekilde güncellersiniz.

  1. overview/OverviewViewModel.kt'yi açın. _response için LiveData öğesinin hemen altına, tek bir MarsProperty nesnesinin hem dahili (değişebilir) hem de harici (sabit) canlı verileri ekleyin.

    İstendiğinde MarsProperty sınıfını (com.example.android.marsrealestate.network.MarsProperty) içe aktarın.
private val _property = MutableLiveData<MarsProperty>()

val property: LiveData<MarsProperty>
   get() = _property
  1. getMarsRealEstateProperties() yönteminde, try/catch {} blokunun içinde _response.value değerini özellik sayısına ayarlayan satırı bulun. Aşağıda gösterilen testi ekleyin. MarsProperty nesnesi kullanılabiliyorsa bu test _property LiveData değerini listResult öğesindeki ilk mülke ayarlar.
if (listResult.size > 0) {   
    _property.value = listResult[0]
}

try/catch {} blokunun tamamı artık şu şekilde görünüyor:

try {
   var listResult = getPropertiesDeferred.await()
   _response.value = "Success: ${listResult.size} Mars properties retrieved"
   if (listResult.size > 0) {      
       _property.value = listResult[0]
   }
 } catch (e: Exception) {
    _response.value = "Failure: ${e.message}"
 }
  1. res/layout/fragment_overview.xml dosyasını açın. <TextView> öğesinde android:text öğesini property LiveData öğesinin imgSrcUrl bileşenine bağlamak için değiştirin:
android:text="@{viewModel.property.imgSrcUrl}"
  1. Uygulamayı çalıştırın. TextView simgesi, yalnızca ilk Mars mülkündeki resmin URL'sini gösterir. Şu ana kadar tek yapmanız gereken, görüntüleme modelini ve bu URL'nin canlı verilerini ayarlamak.

3. Adım: Bir bağlayıcı adaptörü oluşturun ve Kaydır'ı arayın

Artık görüntülenecek resmin URL'sine sahipsiniz ve artık bu resmi yüklemek için Kaydırarak çalışmaya başlayabilirsiniz. Bu adımda, URL'yi bir ImageView ile ilişkilendirilmiş XML özelliğinden almak için bir bağlama adaptörü kullanırsınız ve resmi yüklemek için Kaydırarak kullanırsınız. Bağlama adaptörleri, veriler değiştiğinde özel davranış sağlamak için bir görünüm ve bağlı veriler arasında yer alan uzantı yöntemleridir. Bu durumda özel davranış, URL'deki bir resmi ImageView ürününe yüklemek için Glide'ı çağırmaktır.

  1. BindingAdapters.kt'yi açın. Bu dosya, uygulama genelinde kullandığınız bağlama adaptörlerini içerir.
  2. ImageView ve String parametrelerini alan bir bindImage() işlevi oluşturun. İşlevde @BindingAdapter ile ek açıklama oluşturun. @BindingAdapter açıklaması, bir XML öğesi imageUrl özelliğine sahip olduğunda veri bağlamanın bu bağlama adaptörünün yürütülmesini istediğinizi belirtir.

    İstendiğinde androidx.databinding.BindingAdapter ve android.widget.ImageView içe aktarın.
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {

}
  1. bindImage() işlevinin içinde, imgUrl bağımsız değişkeni için bir let {} bloğu ekleyin:
imgUrl?.let { 
}
  1. URL dizesini (XML'den) bir Uri nesnesine dönüştürmek için let {} blokunun içinde, aşağıda gösterilen satırı ekleyin. İstek üzerine androidx.core.net.toUri içe aktarın.

    Resimleri aldığınız sunucu bu şemayı gerektirdiğinden HTTPS şemasının son Uri nesnesini kullanmasını istiyorsunuz. HTTPS şemasını kullanmak için toUri oluşturucuya buildUpon.scheme("https") ekleyin. toUri() yöntemi, Android KTX temel kitaplığından Kotlin uzantısı işlevidir. Bu nedenle, String sınıfının bir parçasıdır.
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
  1. Hâlâ let {} içinde, Uri nesnesindeki resmi ImageView içine yüklemek üzere Glide.with() çağrısı yapın. İstendiğinde com.bumptech.glide.Glide içe aktarın.
Glide.with(imgView.context)
       .load(imgUri)
       .into(imgView)

4. Adım: Düzeni ve parçaları güncelleyin

Glide resmi yüklemiş olsa da henüz görülecek bir şey yok. Sonraki adım, resmi görüntülemek için düzeni ve parçaları bir ImageView ile güncellemektir.

  1. res/layout/gridview_item.xml'yi açın. Bu, codelab'in ilerleyen kısımlarında RecyclerView içindeki her öğe için kullanacağınız düzen kaynağı dosyasıdır. Yalnızca geçici bir resim göstermek için geçici olarak burada kullanırsınız.
  2. <ImageView> öğesinin üzerine, veri bağlama için bir <data> öğesi ekleyin ve OverviewViewModel sınıfına bağlayın:
<data>
   <variable
       name="viewModel"
       type="com.example.android.marsrealestate.overview.OverviewViewModel" />
</data>
  1. Yeni resim yükleme bağlama adaptörünü kullanmak için ImageView öğesine bir app:imageUrl özelliği ekleyin:
app:imageUrl="@{viewModel.property.imgSrcUrl}"
  1. overview/OverviewFragment.kt'yi açın. onCreateView() yönteminde, FragmentOverviewBinding sınıfını şişiren ve bağlama değişkenine atayan satıra yorum yapın. Bu geçici bir durumdur ve daha sonra tekrar deneyebilirsiniz.
//val binding = FragmentOverviewBinding.inflate(inflater)
  1. Bunun yerine, GridViewItemBinding sınıfını şişirmek için bir satır ekleyin. İstendiğinde com.example.android.marsrealestate. databinding.GridViewItemBinding içe aktarın.
val binding = GridViewItemBinding.inflate(inflater)
  1. Uygulamayı çalıştırın. Artık sonuç listesinde ilk MarsProperty kareye ait fotoğrafın fotoğrafını görürsünüz.

5. Adım: Basit yükleme ve hata resimleri ekleyin

Kaydırarak resim yüklenirken yer tutucu resim, yükleme başarısız olursa (ör. resim eksikse veya bozulmuşsa) bir hata resmi göstererek kullanıcı deneyimini iyileştirebilir. Bu adımda, bu işlevi bağlama adaptörüne ve düzene eklersiniz.

  1. res/drawable/ic_broken_image.xml web sitesini açın ve sağdaki Önizleme sekmesini tıklayın. Hata resmi için, yerleşik simge kitaplığında bulunan bozuk resim simgesini kullanıyorsunuz. Bu vektör çizimi, simgeyi gri yapmak için android:tint özelliğini kullanır.

  1. res/drawable/loading_animation.xml'yi açın. Bu çizim, <animate-rotate> etiketiyle tanımlanan bir animasyondur. Animasyon, bir resmi (loading_img.xml) orta noktanın etrafında çizilebilir. (Animasyonu önizlemede görmezsiniz.)

  1. BindingAdapters.kt dosyasına dönün. bindImage() yönteminde, load() ile into() arasındaki apply() işlevini çağırmak için aramayı Glide.with() olarak güncelleyin. İstendiğinde com.bumptech.glide.request.RequestOptions öğesini içe aktarın.

    Bu kod, yükleme sırasında kullanılacak yer tutucu yükleme resmini (loading_animation çekilebilir) ayarlar. Kod ayrıca, resim yükleme başarısız olursa (broken_image çekilebilir) kullanılacak bir resim ayarlar. Tam bindImage() yöntemi artık şu şekilde görünür:
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {
    imgUrl?.let {
        val imgUri = 
           imgUrl.toUri().buildUpon().scheme("https").build()
        Glide.with(imgView.context)
                .load(imgUri)
                .apply(RequestOptions()
                        .placeholder(R.drawable.loading_animation)
                        .error(R.drawable.ic_broken_image))
                .into(imgView)
    }
}
  1. Uygulamayı çalıştırın. Ağ bağlantınızın hızına bağlı olarak, Kaydırma özelliği indirilirken yükleme resmini kısa bir süre içinde görebilirsiniz. Ancak ağınızı kapatsanız bile bozuk resim simgesini göremezsiniz. Bunu codelab'in son bölümünde düzeltirsiniz.

Uygulamanız artık mülk bilgilerini internette yüklüyor. İlk MarsProperty liste öğesindeki verileri kullanarak görünüm modelinde bir LiveData özelliği oluşturdunuz ve ImageView özelliğini doldurmak için bu mülk verilerinden alınan resim URL'sini kullandınız. Ancak uygulamanızın amacı, resimlerden oluşan bir tablo görüntülemektir. Bu nedenle GridLayoutManager içeren bir RecyclerView kullanmak istersiniz.

1. Adım: Görünüm modelini güncelleyin

Şu anda, görüntüleme modelinde, web hizmetindeki yanıt listesinde ilki olan MarsProperty MarsProperty nesnesini içeren bir _property LiveData bulunmaktadır. Bu adımda, LiveData öğesini MarsProperty nesne listesinin tamamını içerecek şekilde değiştirirsiniz.

  1. overview/OverviewViewModel.kt'yi açın.
  2. Gizli _property değişkenini _properties olarak değiştirin. Türü, MarsProperty nesnelerinin listesi olacak şekilde değiştirin.
private val _properties = MutableLiveData<List<MarsProperty>>()
  1. Harici property canlı verilerini properties ile değiştirin. Listeyi buraya LiveData türüne de ekleyin:
 val properties: LiveData<List<MarsProperty>>
        get() = _properties
  1. Aşağı kaydırarak getMarsRealEstateProperties() yöntemine gidin. try {} blokunun içinde, önceki görevde eklediğiniz testin tamamını aşağıda gösterilen satırla değiştirin. listResult değişkeni bir MarsProperty nesnesinin listesini içerdiğinden, başarılı bir yanıt için test etmek yerine _properties.value öğesini atayabilirsiniz.
_properties.value = listResult

try/catch blokunun tamamı artık şöyle görünür:

try {
   var listResult = getPropertiesDeferred.await()
   _response.value = "Success: ${listResult.size} Mars properties retrieved"
   _properties.value = listResult
} catch (e: Exception) {
   _response.value = "Failure: ${e.message}"
}

2. Adım: Düzenleri ve parçaları güncelleyin

Sonraki adım, tek bir resim görünümü yerine geri dönüşüm görünümü ve ızgara düzeni kullanmak için uygulamanın düzenini ve parçalarını değiştirmektir.

  1. res/layout/gridview_item.xml'yi açın. OverviewViewModel olan veri bağlamayı MarsProperty olarak değiştirin ve değişkeni "property" olarak yeniden adlandırın.
<variable
   name="property"
   type="com.example.android.marsrealestate.network.MarsProperty" />
  1. <ImageView> içinde app:imageUrl özelliğini, MarsProperty nesnesindeki resim URL'sine başvuracak şekilde değiştirin:
app:imageUrl="@{property.imgSrcUrl}"
  1. overview/OverviewFragment.kt'yi açın. onCreateview() yılında FragmentOverviewBinding şişiren satırın açıklamasını kaldırın. GridViewBinding şişiren satırı silin veya şişirin. Bu değişiklikler son görevde geçici olarak yaptığınız değişiklikleri geri alır.
val binding = FragmentOverviewBinding.inflate(inflater)
 // val binding = GridViewItemBinding.inflate(inflater)
  1. res/layout/fragment_overview.xml'yi açın. <TextView> öğesinin tamamını silin.
  2. Bunun yerine, tek bir öğe için GridLayoutManager ve grid_view_item düzenini kullanan bu <RecyclerView> öğesini ekleyin:
<androidx.recyclerview.widget.RecyclerView
            android:id="@+id/photos_grid"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="6dp"
            android:clipToPadding="false"
            app:layoutManager=
               "androidx.recyclerview.widget.GridLayoutManager"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:spanCount="2"
            tools:itemCount="16"
            tools:listitem="@layout/grid_view_item" />

3. Adım: Fotoğraf ızgarası adaptörünü ekleyin

Artık fragment_overview düzeninde RecyclerView, grid_view_item düzeninde ise tek bir ImageView var. Bu adımda, verileri bir RecyclerView adaptörü üzerinden RecyclerView'a bağlarsınız.

  1. overview/PhotoGridAdapter.kt'yi açın.
  2. Oluşturucu parametreleriyle birlikte aşağıda gösterilen PhotoGridAdapter sınıfını oluşturun. PhotoGridAdapter sınıfı, oluşturucunun liste öğesi türü, görüntüleme sahibi ve DiffUtil.ItemCallback uygulamasına ihtiyacı olan ListAdapter kapsamını genişletir.

    İstendiğinde androidx.recyclerview.widget.ListAdapter ve com.example.android.marsrealestate.network.MarsProperty sınıflarını içe aktarın. Aşağıdaki adımlarda, bu oluşturucunun hata oluşturan diğer eksik bölümlerini uyguluyorsunuz.
class PhotoGridAdapter : ListAdapter<MarsProperty,
        PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {

}
  1. onCreateViewHolder() ve onBindViewHolder() olan ListAdapter yöntemlerini uygulamak için PhotoGridAdapter sınıfının herhangi bir yerini tıklayın ve Control+i tuşuna basın.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoGridAdapter.MarsPropertyViewHolder {
   TODO("not implemented") 
}

override fun onBindViewHolder(holder: PhotoGridAdapter.MarsPropertyViewHolder, position: Int) {
   TODO("not implemented") 
}
  1. PhotoGridAdapter sınıf tanımının sonuna, yeni eklediğiniz yöntemlerden sonra, aşağıda gösterildiği gibi DiffCallback için bir tamamlayıcı nesne tanımı ekleyin.

    İstendiğinde androidx.recyclerview.widget.DiffUtil içe aktarın.

    DiffCallback nesnesi DiffUtil.ItemCallback öğesini, karşılaştırmak istediğiniz nesnenin türüyle genişletir.MarsProperty
companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
}
  1. Bu nesne için karşılaştırıcı yöntemlerini uygulamak üzere Control+i tuşuna basın (areItemsTheSame() ve areContentsTheSame()).
override fun areItemsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
   TODO("not implemented") 
}

override fun areContentsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
   TODO("not implemented") }
  1. areItemsTheSame() yöntemi için yapılacaklar listesini kaldırın. Kotlin's yönlendirmeli eşitlik operatörünü (===) kullanın. oldItem ve newItem için nesne referansları aynıysa true sonucunu döndürür.
override fun areItemsTheSame(oldItem: MarsProperty, 
                  newItem: MarsProperty): Boolean {
   return oldItem === newItem
}
  1. areContentsTheSame() için yalnızca oldItem ve newItem kimliğine sahip standart eşitlik operatörünü kullanın.
override fun areContentsTheSame(oldItem: MarsProperty, 
                  newItem: MarsProperty): Boolean {
   return oldItem.id == newItem.id
}
  1. Hâlâ PhotoGridAdapter sınıfının içinde, tamamlayıcı nesnenin altına, RecyclerView.ViewHolder kapsamını genişleten MarsPropertyViewHolder için bir iç sınıf tanımı ekleyin.

    İstendiğinde androidx.recyclerview.widget.RecyclerView ve com.example.android.marsrealestate.databinding.GridViewItemBinding içe aktarın.

    MarsProperty öğesini düzene bağlamak için GridViewItemBinding değişkenini kullanmanız gerekir. Bu nedenle değişkeni MarsPropertyViewHolder öğesine geçirin. Temel ViewHolder sınıfı, oluşturucuda bir görünüm gerektirdiğinden bunu bağlama kök görünümüne geçirirsiniz.
class MarsPropertyViewHolder(private var binding: 
                   GridViewItemBinding):
       RecyclerView.ViewHolder(binding.root) {

}
  1. MarsPropertyViewHolder içinde, MarsProperty nesnesini bağımsız değişken olarak alıp bu nesneyi binding.property olarak ayarlayan bir bind() yöntemi oluşturun. Mülkü ayarladıktan sonra executePendingBindings() öğesini çağırarak güncellemenin hemen yürütülmesini sağlayın.
fun bind(marsProperty: MarsProperty) {
   binding.property = marsProperty
   binding.executePendingBindings()
}
  1. onCreateViewHolder() sayfasında, YAPILACAKLAR bölümünü kaldırın ve aşağıda gösterilen satırı ekleyin. İstendiğinde android.view.LayoutInflater içe aktarın.

    onCreateViewHolder() yönteminin, GridViewItemBinding'ın şişirilmesi ve üst ViewGroup bağlamının LayoutInflater kullanılmasıyla oluşturulan yeni bir MarsPropertyViewHolder döndürmesi gerekir.
   return MarsPropertyViewHolder(GridViewItemBinding.inflate(
      LayoutInflater.from(parent.context)))
  1. onBindViewHolder() yönteminde, YAPILACAKLAR bölümünü kaldırın ve aşağıda gösterilen satırları ekleyin. Burada, mevcut RecyclerView konumuyla ilişkilendirilmiş MarsProperty nesnesini almak için getItem() öğesini çağırır ve ardından bu özelliği MarsPropertyViewHolder içindeki bind() yöntemine geçirirsiniz.
val marsProperty = getItem(position)
holder.bind(marsProperty)

4. Adım: Bağlama adaptörünü ekleyin ve parçaları bağlayın

Son olarak, PhotoGridAdapter öğesini MarsProperty nesneleri listesiyle başlatmak için bir BindingAdapter kullanın. RecyclerView verilerini ayarlamak için BindingAdapter kullanılması, veri bağlamanın MarsProperty nesne listesinde LiveData değerinin otomatik olarak gözlemlenmesine neden olur. Daha sonra, MarsProperty listesi değiştiğinde bağlama adaptörü otomatik olarak çağrılır.

  1. BindingAdapters.kt'yi açın.
  2. Dosyanın sonuna RecyclerView bağımsız değişken olarak bir bindRecyclerView() yöntemi ve MarsProperty nesnelerinin bir listesini ekleyin. Bu yönteme @BindingAdapter ile ek açıklama ekleyin.

    İstendiğinde androidx.recyclerview.widget.RecyclerView ve com.example.android.marsrealestate.network.MarsProperty içe aktarın.
@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, 
    data: List<MarsProperty>?) {
}
  1. bindRecyclerView() işlevinin içinde recyclerView.adapter öğesini PhotoGridAdapter öğesine yayınlayın ve verilerle birlikte adapter.submitList() öğesini çağırın. Bu, RecyclerView adlı kullanıcıya yeni bir liste hazır olduğunda bildirir.

İstendiğinde com.example.android.marsrealestate.overview.PhotoGridAdapter içe aktarın.

val adapter = recyclerView.adapter as PhotoGridAdapter
adapter.submitList(data)
  1. res/layout/fragment_overview.xml'yi açın. app:listData özelliğini RecyclerView öğesine ekleyin ve veri bağlamayı kullanarak viewmodel.properties olarak ayarlayın.
app:listData="@{viewModel.properties}"
  1. overview/OverviewFragment.kt'yi açın. onCreateView() içinde, setHasOptionsMenu() çağrısından hemen önce binding.photosGrid için RecyclerView adaptörünü yeni bir PhotoGridAdapter nesnesine başlatın.
binding.photosGrid.adapter = PhotoGridAdapter()
  1. Uygulamayı çalıştırın. Izgara MarsProperty resim görürsünüz. Yeni resimleri görmek için sayfayı kaydırdığınızda uygulama, resmin kendisini görüntülemeden önce yükleme ilerleme durumu simgesini gösterir. Uçak modunu açarsanız henüz yüklenmeyen resimler bozuk resim simgeleri olarak görünür.

Bir resim getirilemediğinde MarsRealEstate uygulamasında bozuk resim simgesi görüntülenir. Ancak ağ olmadığında uygulama boş bir ekran gösterir.

Bu iyi bir kullanıcı deneyimi değildir. Bu görevde, kullanıcıya neler olduğu hakkında daha iyi bir fikir vermek için temel hata işlemeyi eklersiniz. İnternet yoksa uygulama bağlantı hatası simgesini gösterir. Uygulama, MarsProperty listesini getirirken yükleme animasyonunu gösterir.

1. Adım: Görünüm modeline durum ekleyin

Başlamak için, görünüm modelinde web isteğinin durumunu temsil eden bir LiveData oluşturursunuz. Üç temel nokta vardır: yükleme, başarılı ve başarısız. Yükleme durumu, await() çağrısında veri beklerken gerçekleşir.

  1. overview/OverviewViewModel.kt'yi açın. Dosyanın en üstüne (içe aktarmalardan sonra, sınıf tanımından önce) mevcut tüm durumları temsil eden enum ekleyin:
enum class MarsApiStatus { LOADING, ERROR, DONE }
  1. OverviewViewModel sınıfındaki dahili ve harici _response canlı veri tanımlarını _status olarak yeniden adlandırın. Bu codelab'de daha önce _properties LiveData için destek eklediğiniz için web hizmeti yanıtı tam olarak kullanılmadı. Mevcut değişkenleri takip edebilmek için burada bir LiveData öğesine ihtiyacınız vardır. Böylece yalnızca mevcut değişkenleri yeniden adlandırabilirsiniz.

Ayrıca, String olan türleri MarsApiStatus. olarak değiştir

private val _status = MutableLiveData<MarsApiStatus>()

val status: LiveData<MarsApiStatus>
   get() = _status
  1. getMarsRealEstateProperties() yöntemine ilerleyin ve _response öğesini de _status olarak güncelleyin. "Success" dizesini MarsApiStatus.DONE durumuna, "Failure" dizesini ise MarsApiStatus.ERROR olarak değiştirin.
  2. await() çağrısından önce, try {} blokunun üst kısmına bir MarsApiStatus.LOADING durumu ekleyin. Bu, coroutine çalışırken ve verileri beklerken başlangıç durumudur. try/catch {} blokunun tamamı artık şu şekilde görünüyor:
try {
    _status.value = MarsApiStatus.LOADING
   var listResult = getPropertiesDeferred.await()
   _status.value = MarsApiStatus.DONE
   _properties.value = listResult
} catch (e: Exception) {
   _status.value = MarsApiStatus.ERROR
}
  1. catch {} blokundaki hata durumundan sonra _properties LiveData alanını boş bir listeye ayarlayın. Bu işlem, RecyclerView anahtarını temizler.
} catch (e: Exception) {
   _status.value = MarsApiStatus.ERROR
   _properties.value = ArrayList()
}

2. Adım: ImageView durumu için bir bağlayıcı adaptörü ekleyin

Artık görünüm modelinde bir durumunuz var ancak bu yalnızca bir grup durum. Uygulamanın kendisinin görünmesini nasıl sağlıyorsunuz? Bu adımda, yükleme ve hata durumlarına ilişkin simgeleri görüntülemek için veri bağlamaya bağlı bir ImageView kullanırsınız. Uygulama, yükleme durumunda veya hata durumundayken ImageView öğesi görünür olmalıdır. Uygulamanın yüklenmesi tamamlandığında ImageView görünmez olmalıdır.

  1. BindingAdapters.kt'yi açın. Bağımsız değişken olarak ImageView ve MarsApiStatus değerini alan, bindStatus() adlı yeni bir bağlayıcı adaptörü ekleyin. İstendiğinde com.example.android.marsrealestate.overview.MarsApiStatus içe aktarın.
@BindingAdapter("marsApiStatus")
fun bindStatus(statusImageView: ImageView, 
          status: MarsApiStatus?) {
}
  1. Farklı durumlar arasında geçiş yapmak için bindStatus() yönteminin içine bir when {} ekleyin.
when (status) {

}
  1. when {} içinde, yükleme durumu için bir destek kaydı (MarsApiStatus.LOADING) ekleyin. Bu durumda, ImageView öğesini görünür olarak ayarlayın ve yükleme animasyonunu atayın. Bu, önceki görevde Kayan için kullandığınız animasyonla aynı çizim olabilir. İstendiğinde android.view.View içe aktarın.
when (status) {
   MarsApiStatus.LOADING -> {
      statusImageView.visibility = View.VISIBLE
      statusImageView.setImageResource(R.drawable.loading_animation)
   }
}
  1. Hata durumu için (MarsApiStatus.ERROR) bir destek kaydı ekleyin. LOADING durumunda yaptığınıza benzer şekilde, ImageView durumunu görünür olarak ayarlayın ve bağlantı hatasını çizilebilir olarak yeniden kullanın.
MarsApiStatus.ERROR -> {
   statusImageView.visibility = View.VISIBLE
   statusImageView.setImageResource(R.drawable.ic_connection_error)
}
  1. Bitti durumu için bir destek kaydı ekleyin: MarsApiStatus.DONE. Burada başarılı bir yanıt verdiğinizden gizlemek için ImageView durumunun görünürlüğünü kapatın.
MarsApiStatus.DONE -> {
   statusImageView.visibility = View.GONE
}

3. Adım: Düzene ImageView durumunu ekleyin

  1. res/layout/fragment_overview.xml'yi açın. RecyclerView öğesinin altında, ConstraintLayout altına, aşağıda gösterilen ImageView öğesini ekleyin.

    Bu ImageView, RecyclerView ile aynı kısıtlamalara sahiptir. Ancak genişlik ve yükseklik, görünümü doldurmak için resmi uzatmak yerine wrap_content kullanarak görüntüyü ortalar. Ayrıca, görünüm modelindeki durum özelliği değiştiğinde, görünümün BindingAdapter çağrısı yaptığı app:marsApiStatus özelliğine de dikkat edin.
<ImageView
   android:id="@+id/status_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:marsApiStatus="@{viewModel.status}" />
  1. Eksik bir ağ bağlantısı simüle etmek için emülatörünüzde veya cihazınızda uçak modunu açın. Uygulamayı derleyip çalıştırın ve hata resminin göründüğüne dikkat edin:

  1. Uygulamayı kapatmak ve uçak modunu kapatmak için Geri düğmesine dokunun. Uygulamayı döndürmek için son kullanılan ekranlarından yararlanın. Ağ bağlantınızın hızına bağlı olarak, resimler yüklenmeye başlamadan önce uygulama web hizmetini sorgularken son derece kısa bir yükleme döner simgesi görebilirsiniz.

Android Studio projesi: MarsRealEstateEnlem

  • Resimleri yönetme sürecini basitleştirmek için Kaydırma kitaplığını kullanarak uygulamanızda resimleri indirin, arabelleğe alın, kodunu çözün ve önbelleğe alın.
  • Glide, internetten bir resim yüklemek için iki şeye ihtiyaç duyar: bir resmin URL'si ve resmin yerleştirileceği ImageView nesnesi. Bu seçenekleri belirtmek için Kaydırarak load() ve into() yöntemlerini kullanın.
  • Bağlama adaptörleri, bir görünüm ile görünüm sınırı verileri arasında yer alan uzantı yöntemleridir. Bağlama adaptörleri, veriler değiştiğinde özel bir davranış sağlar (örneğin, bir URL'den ImageView içerisine resim yüklemek için Glide'ı çağırmak).
  • Bağlama adaptörleri, @BindingAdapter ek açıklamasıyla birlikte kullanılan uzantı yöntemleridir.
  • Kaydırma isteğine seçenek eklemek için apply() yöntemini kullanın. Örneğin, bir yükleme çekilebilirliğini belirtmek için placeholder() ile apply(), çekilebilir bir hata belirtmek içinse error() ile birlikte apply() kullanın.
  • Izgara resim oluşturmak için GridLayoutManager içeren bir RecyclerView kullanın.
  • Değiştiğinde özellik listesini güncellemek için RecyclerView ile düzen arasında bir bağlayıcı adaptörü 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

Yüklenen resmi içeren ImageView öğesini belirtmek için hangi Kaydırma yöntemini kullanıyorsunuz?

makbuz into()

makbuz with()

makbuz imageview()

makbuz apply()

2. Soru

Glide yüklenirken gösterilecek bir yer tutucu resmi nasıl belirtirsiniz?

▢ Çizilebilir into() yöntemini kullanın.

RequestOptions() yöntemini kullanın ve placeholder() yöntemini çekilebilir olarak çağırın.

Glide.placeholder özelliğini çekilebilir duruma atayın.

RequestOptions() yöntemini kullanın ve loadingImage() yöntemini çekilebilir olarak çağırın.

3. Soru

Bir yöntemin bağlayıcı adaptörü olduğunu nasıl belirtirsiniz?

LiveData üzerindeki setBindingAdapter() yöntemini arayın.

▢ Yöntemi BindingAdapters.kt adlı bir Kotlin dosyasına koyun.

▢ XML düzeninde android:adapter özelliğini kullanın.

▢ Yönteme @BindingAdapter ile ek açıklama ekleyin.

Sonraki derse başlayın: 8.3 İnternet verileriyle filtreleme ve ayrıntı görünümleri

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.