Android Kotlin Hakkında Temel Bilgiler 08.2: İnternetten resim yükleme ve görüntüleme

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ş

Önceki codelab'de, bir web hizmetinden nasıl veri alacağınızı ve yanıtı nasıl ayrıştırarak veri nesnesine dönüştüreceğinizi öğrendiniz. Bu codelab'de, web URL'sindeki fotoğrafları yüklemek ve görüntülemek için bu bilgileri kullanacaksınız. Ayrıca, RecyclerView oluşturma ve bunu genel bakış sayfasında bir resim ızgarası görüntülemek için kullanma konusunu da tekrar ele alacaksınız.

Bilmeniz gerekenler

  • Parçacık 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şenleri kullanma
  • Retrofit ve Moshi kitaplıklarını kullanarak bir REST web hizmetinden JSON'ı nasıl alacağınızı ve bu verileri Kotlin nesnelerine nasıl ayrıştıracağınızı öğrenin.
  • RecyclerView ile ızgara düzeni oluşturma
  • Adapter, ViewHolder ve DiffUtil nasıl çalışır?

Neler öğreneceksiniz?

  • Web URL'sindeki bir resmi yüklemek ve görüntülemek için Glide kitaplığı nasıl kullanılır?
  • Resim tablosu görüntülemek için RecyclerView ve ızgara adaptörü kullanma
  • Resimler indirilirken ve görüntülenirken olası hataların nasıl ele alınacağı.

Yapacaklarınız

  • MarsRealEstate uygulamasını, Mars mülk verilerinden resim URL'sini alacak ve bu resmi yükleyip görüntülemek için Glide'ı kullanacak şekilde değiştirin.
  • Uygulamaya yükleme animasyonu ve hata simgesi ekleyin.
  • Mars'taki tesislerin resimlerinden oluşan bir ızgara göstermek için RecyclerView kullanın.
  • RecyclerView öğesine durum ve hata işleme ekleyin.

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. 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.

Bu codelab'de oluşturduğunuz uygulama sürümü, resimlerden oluşan bir ızgara gösteren genel bakış sayfasını doldurur. 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 Glide kitaplığını, resimler için ızgara düzeni oluşturmak üzere de RecyclerView kullanır. Uygulamanız, ağ hatalarını da sorunsuz bir şekilde işler.

Web URL'sinden fotoğraf göstermek basit bir işlem gibi görünse de iyi çalışması için önemli bir mühendislik çalışması gerekir. Resmin, sıkıştırılmış biçiminden Android'in kullanabileceği bir resme dönüştürülmesi için indirilmesi, arabelleğe alınması ve kodunun çözülmesi gerekir. Resim, bellek içi önbelleğe, depolama tabanlı önbelleğe veya her ikisine de önbelleğe alınmalıdır. Tüm bu işlemler, kullanıcı arayüzünün yanıt vermeye devam etmesi için düşük öncelikli arka plan iş parçacıklarında gerçekleşmelidir. Ayrıca, en iyi ağ ve CPU performansı için birden fazla resmi aynı anda getirmek ve kodunu çözmek isteyebilirsiniz. Resimleri ağdan etkili bir şekilde yüklemeyi öğrenmek başlı başına bir kod laboratuvarı olabilir.

Neyse ki resimlerinizi indirmek, arabelleğe almak, kodunu çözmek ve önbelleğe almak için Glide adlı topluluk tarafından geliştirilmiş bir kitaplığı kullanabilirsiniz. Glide, tüm bunları sıfırdan yapmanız gerektiğinde karşılaşacağınız iş yükünü önemli ölçüde azaltır.

Glide'ın temel olarak iki şeye ihtiyacı vardır:

  • 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 resmi görüntülemek için Glide'ı nasıl kullanacağınızı öğreneceksiniz. Web hizmetinin döndürdüğü mülkler listesinde ilk Mars mülkünü temsil eden resmi gösterirsiniz. Önceki ve sonraki ekran görüntülerini aşağıda bulabilirsiniz:

1. adım: Glide bağımlılığını ekleyin

  1. Son codelab'deki MarsRealEstate uygulamasını açın. (Uygulama yoksa MarsRealEstateNetwork'ü buradan indirebilirsiniz.)
  2. Uygulamanın ne yaptığını görmek için uygulamayı çalıştırın. (Mars'ta varsayımsal olarak mevcut olan bir mülkün metin ayrıntılarını gösterir.)
  3. build.gradle (Module: app) dosyasını açın.
  4. dependencies bölümünde Glide kitaplığı için şu 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 Şimdi Senkronize Et'i tıklayın.

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

Ardından, tek bir Mars tesisi için canlı verileri içerecek şekilde OverviewViewModel sınıfını güncellersiniz.

  1. overview/OverviewViewModel.kt adlı kişiyi aç. _response için LiveData simgesinin hemen altına tek bir MarsProperty nesnesi için hem dahili (değişebilir) hem de harici (değişmez) canlı veriler 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, _response.value değerini özellik sayısına ayarlayan try/catch {} bloğunun içindeki satırı bulun. Aşağıdaki testi ekleyin. MarsProperty nesneleri varsa bu test, _property LiveData özelliğinin değerini listResult içindeki ilk mülk olarak ayarlar.
if (listResult.size > 0) {   
    _property.value = listResult[0]
}

Tam try/catch {} bloğu 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 değerini property LiveData öğesinin imgSrcUrl bileşenine bağlanacak şekilde değiştirin:
android:text="@{viewModel.property.imgSrcUrl}"
  1. Uygulamayı çalıştırın. TextView yalnızca ilk Mars mülkündeki resmin URL'sini gösterir. Şimdiye kadar yaptığınız tek şey, görünüm modelini ve bu URL'nin canlı verilerini ayarlamaktı.

3. adım: Bağlama bağdaştırıcısı oluşturun ve Glide'ı çağırın

Artık görüntülenecek bir resmin URL'sine sahipsiniz ve bu resmi yüklemek için Glide ile çalışmaya başlamanın zamanı geldi. Bu adımda, ImageView ile ilişkili bir XML özelliğinden URL'yi almak için bağlama bağdaştırıcısı kullanır ve resmi yüklemek için Glide'ı kullanırsınız. Bağlama bağdaştırıcıları, veri değiştiğinde özel davranış sağlamak için bir görünüm ile bağlı veriler arasında yer alan uzantı yöntemleridir. Bu durumda, özel davranış, bir URL'den resim yüklemek için Glide'ı çağırmaktır.ImageView

  1. BindingAdapters.kt adlı kişiyi aç. Bu dosya, uygulama genelinde kullandığınız bağlama bağdaştırıcılarını içerir.
  2. bindImage() işlevi oluşturun. Bu işlev, parametre olarak ImageView ve String değerlerini alır. İşlevi @BindingAdapter ile açıklama ekleyin. @BindingAdapter açıklaması, veri bağlamaya bir XML öğesinde imageUrl özelliği olduğunda bu bağlama bağdaştırıcısının yürütülmesini istediğinizi bildirir. İstendiğinde

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

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

    Resimleri çektiğiniz sunucu bu şemayı gerektirdiğinden son Uri nesnesinin HTTPS şemasını kullanmasını istiyorsunuz. HTTPS şemasını kullanmak için buildUpon.scheme("https") oluşturucuya toUri ekleyin. toUri() yöntemi, Android KTX çekirdek kitaplığındaki bir Kotlin uzantı işlevidir. Bu nedenle, yalnızca String sınıfının bir parçası gibi görünür.
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
  1. Hâlâ let {} içindeyseniz Uri nesnesindeki resmi ImageView'e yüklemek için Glide.with()'i çağırı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östermek için düzeni ve parçaları ImageView ile güncellemek.

  1. res/layout/gridview_item.xml adlı kişiyi aç. Bu, codelab'in ilerleyen bölümlerinde RecyclerView içindeki her öğe için kullanacağınız düzen kaynak dosyasıdır. Tek bir resmi göstermek için burada geçici olarak kullanırsınız.
  2. <ImageView> öğesinin üstüne, 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 bağdaştırıcısını kullanmak için ImageView öğesine bir app:imageUrl özelliği ekleyin:
app:imageUrl="@{viewModel.property.imgSrcUrl}"
  1. overview/OverviewFragment.kt adlı kişiyi aç. onCreateView() yönteminde, FragmentOverviewBinding sınıfını şişiren ve bağlama değişkenine atayan satırı yorum satırı yapın. Bu yalnızca geçici bir durumdur. Daha sonra bu hesaba geri döneceksiniz.
//val binding = FragmentOverviewBinding.inflate(inflater)
  1. Bunun yerine GridViewItemBinding sınıfını yükseltmek 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. Sonuç listesinde ilk MarsProperty öğesindeki resmin fotoğrafını görürsünüz.

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

Glide, resmi yüklerken yer tutucu bir resim, yükleme başarısız olursa (ör. resim eksik veya bozuksa) ise 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 simgesini 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 drawable vektör, simgeyi gri renkte göstermek için android:tint özelliğini kullanır.

  1. res/drawable/loading_animation.xml adlı kişiyi aç. Bu drawable, <animate-rotate> etiketiyle tanımlanan bir animasyondur. Animasyon, çizilebilir bir resmi (loading_img.xml) orta nokta etrafında döndürür. (Önizlemede animasyonu görmezsiniz.)

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

    Bu kod, yükleme sırasında kullanılacak yer tutucu yükleme resmini (loading_animation çizilebilir öğesi) ayarlar. Kod, resim yükleme başarısız olursa kullanılacak bir resim de ayarlar (broken_image çizilebilir). bindImage() yönteminin tamamı 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, Glide mülk resmini indirip gösterirken yükleme resmini kısa bir süre görebilirsiniz. Ancak ağınızı kapatsanız bile bozuk resim simgesini henüz görmezsiniz. Bu sorunu codelab'in son bölümünde düzelteceksiniz.

Uygulamanız artık internetten mülk bilgilerini yüklüyor. İlk MarsProperty liste öğesindeki verileri kullanarak görünüm modelinde bir LiveData özelliği oluşturdunuz ve bir ImageView öğesini doldurmak için bu özellik verilerindeki resim URL'sini kullandınız. Ancak hedefiniz uygulamanızın bir resim ızgarası göstermesi olduğundan RecyclerView ile GridLayoutManager kullanmak istersiniz.

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

Şu anda görünüm modelinde, web hizmetinden gelen yanıt listesindeki ilk MarsProperty nesnesini tutan bir _property LiveData var. Bu adımda, LiveData öğesini MarsProperty nesnelerinin tamamını içerecek şekilde değiştirirsiniz.

  1. overview/OverviewViewModel.kt adlı kişiyi aç.
  2. Özel _property değişkenini _properties olarak değiştirin. Türü MarsProperty nesnelerinin listesi olarak değiştirin.
private val _properties = MutableLiveData<List<MarsProperty>>()
  1. Harici property canlı verilerini properties ile değiştirin. Listeyi LiveData türüne de ekleyin:
 val properties: LiveData<List<MarsProperty>>
        get() = _properties
  1. getMarsRealEstateProperties() yöntemine gidin. try {} bloğunun içinde, önceki görevde eklediğiniz testin tamamını aşağıdaki satırla değiştirin. listResult değişkeni MarsProperty nesnelerinin listesini içerdiğinden başarılı bir yanıt için test etmek yerine bunu _properties.value değişkenine atayabilirsiniz.
_properties.value = listResult

try/catch bloğunun tamamı artık şu şekilde görünüyor:

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

Bir sonraki adım, uygulamanın düzenini ve parçalarını tek resim görünümü yerine geri dönüşüm görünümü ve ızgara düzeni kullanacak şekilde değiştirmektir.

  1. res/layout/gridview_item.xml adlı kişiyi aç. Veri bağlamayı OverviewViewModel olarak değiştirin ve değişkeni "property" olarak yeniden adlandırın.MarsProperty
<variable
   name="property"
   type="com.example.android.marsrealestate.network.MarsProperty" />
  1. <ImageView> bölümünde, app:imageUrl özelliğini MarsProperty nesnesindeki resim URL'sine referans verecek şekilde değiştirin:
app:imageUrl="@{property.imgSrcUrl}"
  1. overview/OverviewFragment.kt adlı kişiyi aç. onCreateview() içinde, FragmentOverviewBinding öğesini genişleten satırın yorum işaretini kaldırın. GridViewBinding değerini artıran satırı silin veya yorum satırı haline getirin. Bu değişiklikler, son görevde yaptığınız geçici değişiklikleri geri alır.
val binding = FragmentOverviewBinding.inflate(inflater)
 // val binding = GridViewItemBinding.inflate(inflater)
  1. res/layout/fragment_overview.xml adlı kişiyi aç. <TextView> öğesinin tamamını silin.
  2. Bunun yerine, tek bir öğe için GridLayoutManager ve grid_view_item düzenini kullanan şu <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, RecyclerView adaptörü aracılığıyla verileri RecyclerView öğesine bağlarsınız.

  1. overview/PhotoGridAdapter.kt adlı kişiyi aç.
  2. Aşağıda gösterilen oluşturucu parametreleriyle PhotoGridAdapter sınıfını oluşturun. PhotoGridAdapter sınıfı, oluşturucusu liste öğesi türünü, görünüm tutucuyu ve DiffUtil.ItemCallback uygulamasını gerektiren ListAdapter sınıfı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 kısımlarını uygulayacaksınız.
class PhotoGridAdapter : ListAdapter<MarsProperty,
        PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {

}
  1. PhotoGridAdapter sınıfında herhangi bir yeri tıklayın ve onCreateViewHolder() ile onBindViewHolder() olan ListAdapter yöntemlerini uygulamak için 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 sonunda, az önce eklediğiniz yöntemlerden sonra, aşağıda gösterildiği gibi DiffCallback için bir tamamlayıcı nesne tanımı ekleyin. İstendiğinde

    İçe aktar'ı androidx.recyclerview.widget.DiffUtil tıklayın.

    The DiffCallback object extends DiffUtil.ItemCallback with the type of object you want to compare—MarsProperty.
companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
}
  1. Bu nesne için karşılaştırıcı yöntemleri (areItemsTheSame() ve areContentsTheSame()) uygulamak üzere Control+i tuşuna basın.
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 YAPILACAKLAR'ı kaldırın. === ve newItem için nesne referansları aynıysa true değerini döndüren Kotlin'in referans eşitliği operatörünü (===) kullanın.oldItem
override fun areItemsTheSame(oldItem: MarsProperty, 
                  newItem: MarsProperty): Boolean {
   return oldItem === newItem
}
  1. areContentsTheSame() için yalnızca oldItem ve newItem kimliğinde 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çindeyken, yardımcı nesnenin altına RecyclerView.ViewHolder sınıfı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 öğelerini içe aktarın.

    MarsProperty öğesini düzene bağlamak için GridViewItemBinding değişkenine ihtiyacınız vardır. Bu nedenle, değişkeni MarsPropertyViewHolder öğesine iletin. Temel ViewHolder sınıfı, oluşturucusunda bir görünüm gerektirdiğinden bağlama kök görünümünü iletirsiniz.
class MarsPropertyViewHolder(private var binding: 
                   GridViewItemBinding):
       RecyclerView.ViewHolder(binding.root) {

}
  1. MarsPropertyViewHolder içinde, MarsProperty nesnesini bağımsız değişken olarak alan ve binding.property değerini bu nesneye ayarlayan bir bind() yöntemi oluşturun. Mülkü ayarladıktan sonra executePendingBindings() işlevini çağırın. Bu işlem, güncellemenin hemen yürütülmesine neden olur.
fun bind(marsProperty: MarsProperty) {
   binding.property = marsProperty
   binding.executePendingBindings()
}
  1. onCreateViewHolder() içinde TODO'yu kaldırın ve aşağıda gösterilen satırı ekleyin. İstendiğinde android.view.LayoutInflater içe aktarın.

    onCreateViewHolder() yöntemi, GridViewItemBinding şişirilerek ve üst ViewGroup bağlamınızdaki LayoutInflater kullanılarak oluşturulan yeni bir MarsPropertyViewHolder döndürmelidir.
   return MarsPropertyViewHolder(GridViewItemBinding.inflate(
      LayoutInflater.from(parent.context)))
  1. onBindViewHolder() yönteminde, TODO'yu kaldırın ve aşağıda gösterilen satırları ekleyin. Burada, geçerli RecyclerView konumuyla ilişkili MarsProperty nesnesini almak için getItem() işlevini çağırır ve ardından bu özelliği MarsPropertyViewHolder içindeki bind() yöntemine iletirsiniz.
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 nesnelerinin listesiyle başlatmak için BindingAdapter kullanın. BindingAdapter kullanarak RecyclerView verilerini ayarlamak, veri bağlamanın MarsProperty nesnelerinin listesi için LiveData öğesini otomatik olarak gözlemlemesine neden olur. Ardından, MarsProperty listesi değiştiğinde bağlama bağdaştırıcısı otomatik olarak çağrılır.

  1. BindingAdapters.kt adlı kişiyi aç.
  2. Dosyanın sonuna, bağımsız değişken olarak RecyclerView ve MarsProperty nesnelerinin listesini alan bir bindRecyclerView() yöntemi ekleyin. Bu yöntemi @BindingAdapter ile açıklayın. İstendiğinde

    Import androidx.recyclerview.widget.RecyclerView ve com.example.android.marsrealestate.network.MarsProperty'ı tıklayın.
@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, 
    data: List<MarsProperty>?) {
}
  1. bindRecyclerView() işlevinin içinde recyclerView.adapter öğesini PhotoGridAdapter olarak yayınlayın ve verilerle adapter.submitList() öğesini çağırın. Bu, yeni bir liste kullanıma sunulduğunda RecyclerView'a bilgi verir.

İ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 adlı kişiyi aç. app:listData özelliğini RecyclerView öğesine ekleyin ve veri bağlama kullanarak viewmodel.properties olarak ayarlayın.
app:listData="@{viewModel.properties}"
  1. overview/OverviewFragment.kt adlı kişiyi aç. onCreateView() içinde, setHasOptionsMenu() çağrısından hemen önce RecyclerView bağdaştırıcısını binding.photosGrid içinde yeni bir PhotoGridAdapter nesnesi olarak başlatın.
binding.photosGrid.adapter = PhotoGridAdapter()
  1. Uygulamayı çalıştırın. MarsProperty resimlerinden oluşan bir tablo görürsünüz. Yeni resimleri görmek için kaydırdığınızda uygulama, resmi göstermeden önce yükleme ilerleme durumu simgesini gösterir. Uçak modunu açarsanız henüz yüklenmemiş resimler bozuk resim simgeleri olarak görünür.

MarsRealEstate uygulaması, bir resim getirilemediğinde bozuk resim simgesini gösteriyor. Ancak ağ olmadığında uygulama boş bir ekran gösteriyor.

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şleme işlevini ekleyeceksiniz. İnternet bağlantısı yoksa uygulamada bağlantı hatası simgesi gösterilir. Uygulama, MarsProperty listesini getirirken yükleme animasyonunu gösterir.

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

Başlamak için, web isteğinin durumunu temsil etmek üzere görünüm modelinde bir LiveData oluşturursunuz. Göz önünde bulundurulması gereken üç durum vardır: yükleme, başarılı ve başarısız. Yükleme durumu, await() çağrısındaki verileri beklerken gerçekleşir.

  1. overview/OverviewViewModel.kt adlı kişiyi aç. Dosyanın en üstüne (içe aktarmalardan sonra, sınıf tanımından önce) tüm kullanılabilir durumları temsil eden bir enum ekleyin:
enum class MarsApiStatus { LOADING, ERROR, DONE }
  1. _response sınıfındaki hem dahili hem de harici OverviewViewModel canlı veri tanımlarını _status olarak yeniden adlandırın. Bu codelab'in önceki bölümlerinde _properties LiveData için destek eklediğinizden, web hizmeti yanıtının tamamı kullanılmamıştır. Mevcut durumu takip etmek için buraya bir LiveData eklemeniz gerekir. Bu nedenle, mevcut değişkenleri yeniden adlandırabilirsiniz.

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

private val _status = MutableLiveData<MarsApiStatus>()

val status: LiveData<MarsApiStatus>
   get() = _status
  1. getMarsRealEstateProperties() yöntemine gidin ve _response ile _status arasındaki farkı burada da güncelleyin. "Success" dizesini MarsApiStatus.DONE durumuna, "Failure" dizesini ise MarsApiStatus.ERROR olarak değiştirin.
  2. MarsApiStatus.LOADING durumunu try {} bloğunun en üstüne, await() çağrısından önce ekleyin. Bu, eş yordam çalışırken ve verileri beklerkenki ilk durumdur. Tam try/catch {} bloğu 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 {} bloğundaki hata durumundan sonra _properties LiveData öğesini boş bir listeye ayarlayın. Bu işlem RecyclerView temizler.
} catch (e: Exception) {
   _status.value = MarsApiStatus.ERROR
   _properties.value = ArrayList()
}

2. adım: Durum ImageView için bir bağlama bağdaştırıcısı ekleyin

Artık görünüm modelinde bir durumunuz var ancak bu yalnızca bir durum kümesi. Bunu uygulamanın kendisinde nasıl gösterebilirsiniz? Bu adımda, yükleme ve hata durumları için simgeler göstermek üzere veri bağlamaya bağlı bir ImageView kullanırsınız. Uygulama yükleme veya hata durumundayken ImageView görünür olmalıdır. Uygulama yüklendiğinde ImageView görünmez olmalıdır.

  1. BindingAdapters.kt adlı kişiyi aç. bindStatus() adlı yeni bir bağlama bağdaştırıcısı ekleyin. Bu bağdaştırıcı, bağımsız değişken olarak ImageView ve MarsApiStatus değerlerini alır. İ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 when {} yönteminin içine bindStatus() ekleyin.
when (status) {

}
  1. when {} içinde yükleme durumu için bir durum ekleyin (MarsApiStatus.LOADING). Bu durum için ImageView öğesini görünür olarak ayarlayın ve yükleme animasyonunu atayın. Bu, önceki görevde Glide için kullandığınız animasyon çizilebilir öğesiyle aynıdır. İ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 bir durum ekleyin. Hata durumu MarsApiStatus.ERROR'dır. LOADING durumu için yaptığınız gibi, durumu ImageView olarak ayarlayın ve bağlantı hatası çizilebilir öğesini yeniden kullanın.
MarsApiStatus.ERROR -> {
   statusImageView.visibility = View.VISIBLE
   statusImageView.setImageResource(R.drawable.ic_connection_error)
}
  1. Tamamlandı durumu için bir durum ekleyin (MarsApiStatus.DONE). Burada başarılı bir yanıt var. Bu nedenle, durumu gizlemek için ImageView durumunun görünürlüğünü kapatın.
MarsApiStatus.DONE -> {
   statusImageView.visibility = View.GONE
}

3. adım: Durum ImageView'ı düzene ekleyin

  1. res/layout/fragment_overview.xml adlı kişiyi aç. RecyclerView öğesinin altında, ConstraintLayout öğesinin içine aşağıda gösterilen ImageView öğesini ekleyin.

    Bu ImageView öğesi, RecyclerView öğesiyle aynı kısıtlamalara sahiptir. Ancak genişlik ve yükseklik, görüntüyü doldurmak için resmi uzatmak yerine resmi ortalamak için wrap_content kullanır. Ayrıca, görünüm modelindeki durum özelliği değiştiğinde app:marsApiStatus görünümünüze yapılan görünüm çağrısını içeren BindingAdapter ö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 ağ bağlantısını 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üğünü fark edin:

  1. Uygulamayı kapatmak için Geri düğmesine dokunun ve uçak modunu kapatın. Uygulamayı döndürmek için son kullanılanlar ekranını kullanın. Ağ bağlantınızın hızına bağlı olarak, resimler yüklenmeye başlamadan önce uygulama web hizmetini sorguladığında çok kısa süreli bir yükleme çarkı görebilirsiniz.

Android Studio projesi: MarsRealEstateGrid

  • Resim yönetme sürecini basitleştirmek için uygulamanızdaki resimleri indirmek, arabelleğe almak, kodunu çözmek ve önbelleğe almak üzere Glide kitaplığını kullanın.
  • Glide, internetten bir resim yüklemek için iki şeye ihtiyaç duyar: resmin URL'si ve resmi yerleştireceği bir ImageView nesnesi. Bu seçenekleri belirtmek için Glide ile load() ve into() yöntemlerini kullanın.
  • Bağlama bağdaştırıcıları, bir görünüm ile bu görünümün bağlı verileri arasında yer alan uzantı yöntemleridir. Bağlama bağdaştırıcıları, veriler değiştiğinde özel davranışlar sağlar. Örneğin, bir URL'den bir ImageView içine resim yüklemek için Glide'ı çağırmak gibi.
  • Bağlama adaptörleri, @BindingAdapter ek açıklamasıyla açıklama eklenmiş uzantı yöntemleridir.
  • Glide isteğine seçenek eklemek için apply() yöntemini kullanın. Örneğin, yükleme çizilebilir öğesini belirtmek için apply() ile placeholder()'i, hata çizilebilir öğesini belirtmek için apply() ile error()'ı kullanın.
  • Resimlerden oluşan bir ızgara oluşturmak için RecyclerView ile GridLayoutManager kullanın.
  • Özellikler listesi değiştiğinde güncel kalması için RecyclerView ile düzen arasında bir bağlama bağdaştırıcısı 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

Yüklenen resmi içerecek ImageView öğesini belirtmek için hangi Glide yöntemini kullanıyorsunuz?

into()

with()

imageview()

apply()

2. Soru

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

into() yöntemini çizilebilir bir öğeyle kullanın.

RequestOptions() kullanın ve placeholder() yöntemini çizilebilir bir öğeyle çağırın.

Glide.placeholder özelliğini çizilebilir bir öğeye atayın.

RequestOptions() kullanın ve loadingImage() yöntemini çizilebilir bir öğeyle çağırın.

3. Soru

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

LiveData üzerinde setBindingAdapter() yöntemini çağırın.

▢ Yöntemi BindingAdapters.kt adlı bir Kotlin dosyasına yerleştirin.

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

▢ Yöntemi @BindingAdapter ile açıklayın.

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ını Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında bulabilirsiniz.