Android Paging Kütüphanesi

ESRA KAYA
Ekmob Developer Studio
4 min readOct 22, 2019

Paging kütüphanesi, tek seferde küçük veri parçaları yüklemenize ve görüntülemenize yardımcı olur. İsteğe bağlı olarak daha fazla veri parçası yükleyebilir bu sayede sistem kaynaklarını daha performanslı kullanabilirsiniz.

PagedList

Paging kütüphanesinin temel bileşeni verilerinizin parçalarını yüklemeye yarayan PagedList sınıfıdır. Daha fazla veri gerektiğinde mevcut olan PagedList objesine disk belleği eklenir. Yüklenen herhangi bir veri değişirse yeni bir PagedList örneği, LiveData veya RxJava2 tabanlı bir nesneden observable data holder’a gönderilir. PagedList nesneleri oluştukça UI lifecycle’ları zarar görmeden yeni içerik gösterilebilir.

Şimdi LiveData ile birlikte ufak bir kod parçacığı inceleyelim.

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {
val concertList: LiveData<PagedList<Concert>> =
concertDao.concertsByDate().toLiveData(pageSize = 50)
}

Yukarıdaki örnekte sayfa başına 50 item içeren bir PagedList nesnesi oluşturur.

Data

PagedList’in her bir örneği, uygulamadaki verilerinizin anlık bir görüntüsünü DataSource nesnesinden yükler. Veriler uygulamanızın backendinden veya veritabanından PagedList nesnesine akar.

Şimdi verileri düzenlemek için Room kullanılmış bir örnek görelim. Siz kendi verilerinizi farklı şekillerde saklayabilirsiniz.

@Dao
interface ConcertDao {
// The Int type parameter tells Room to use a PositionalDataSource object.
@Query("SELECT * FROM concerts ORDER BY date DESC")
fun concertsByDate(): DataSource.Factory<Int, Concert>
}

UI

PagedList sınıfı, bir RecyclerView içine öğe yüklemek için PagedListAdapter ile çalışır. Bu iki sınıf, içeriği yüklendiği sırada almak ve görüntülemek için birlikte çalışırlar.

Paging kütüphanesi cihaz içinde tutulan veriler, uzak sunucudan gelen veriler veya her ikisinin birlikte kombine edildiği farklı veri mimarilerini destekler.

Yukarıdaki resimde bu mimari senaryolarının her birinde verinin nasıl aktarıldığı gösterilmektedir. Yalnızca ağ veya veritabanı çözümü kullandığınızda veriler doğrudan uygulamanızın UI modeline aktarılır. Eğer ikisinin bir arada olduğu bir kullanımınız varsa veriler backend sunucunuzdan cihazdaki veritabanına ve ardından UI modeline akar. Bu süreçte her veri akışının bitiş noktasında veri sağlayıcısından daha fazla veri talep edilir. Örneğin cihaz içerisindeki veri tabanındaki veri bittiğinde sunucudan daha fazla veri ister.

Ağ Hataları
Paging kütüphanesini kullanırken ağın kullanılabilir veya kullanılamaz durumda olmasının dışında farklı durumlarda olabilir. Örneğin belirli bir sunucu ağ isteğine yanıt vermede başarısız olabilir ya da cihaz zayıf, yavaş bir şebekeye bağlı olabilir. Bu gibi durumlarda her bir isteği hata için kontrol etmeli ve durumu verilerin yüklenemediği noktada “yeniden dene” gibi butonlar koyarak kurtarmalısınız.

Mevcut uygulamanızı nasıl güncelleyebilirsiniz

Zaten mevcut olan uygulamanız içerisinde bir veritabanından ya da backend servisinden veri sağlanıyorsa bu yapıyı Paging kütüphanesine geçirmek mümkündür. Bunun için neler yapabiliriz bir bakalım.

Özel sayfalama çözümleri
Uygulamanızda büyük verileri küçük parçalar halinde çekmek için özel işlevler kullanıyorsanız, bu mantığı PagedList sınıfındakiyle değiştirebilirsiniz. PagedList örnekleri, kullanıcı arayüzüne dahil edebileceğiniz RecyclerView nesneleri için adaptör sağlar.

Sayfalar yerine listeler kullanılarak yüklenen veriler
Adaptörünüzde veri yapısı olarak bellekte saklanan bir liste kullanıyorsanız ve bu listedeki öğelerin sayısı fazla ise bir PagedList sınıfı kullanarak veri güncellemelerini gözlemleyebilirsiniz. PagedList örnekleri, veri güncellemelerini uygulamanızın kullanıcı arayüzüne aktarmak için LiveData<PagedList> veya Observable<List> kullanır, bu sayede yükleme sürelerini ve bellek kullanımını en aza indirir. Ve bütün bunları yaparken List nesnesi yerine PagedList nesnesi kullandığınızda kullanıcı arayüzünde veya veri güncelleme mantığındaki bir değişiklik yapmanız gerekmez.

Veri imlecini CursorAdapter kullanarak liste görünümüyle ilişkilendirme
Uygulamanız bir Cursor’dan gelen verileri ListView ile ilişkilendirmek için bir cursorAdapter kullanıyor olabilir. Bu durumda ListView yerine RecyclerView kullanmalısınız. Daha sonra Cursor bileşenin herhangi bir SQLite veritabanına erişip erişmediğine bağlı olarak Room veya PositionalDataSource ile değiştirin.

Spinner örnekleriyle çalışırken olduğu gibi bazı durumlarda, yalnızca adaptörün kendisini sağlarsınız. Bir kütüphane daha sonra bu adaptöre yüklenen verileri alır ve sizin için veriyi görüntüler. Bu durumlarda adapterınızdaki verilerin türünü LiveData<PagedList> olarak değiştirin. Daha sonra bu listeyi kütüphaneye vermeden önce ArrayAdapter nesnesine gömün.

AsyncListUtil kullanarak içeriği asynchronous olarak yükleme
Bilgi gruplarını asynchronous olarak yüklemek ve görüntülemek için AsyncListUtil nesnelerini kullanıyorsanız, Paging Kütüphanesi verileri daha kolay yüklemenizi sağlar:

Bunun için verilerinizin konumlandırılmış olması gerekmez. Paging Kütüphanesi, ağın sağladığı anahtar noktaları kullanarak doğrudan backendden veri yüklemenizi sağlar.

Verileriniz hesap edilemez derecede büyük olabilir. Paging Kitaplığı’nı kullanarak, kalan herhangi bir veri olmayana kadar hepsini sayfalara yükleyebilirsiniz.

Verilerinizi daha kolay gözlemleyebilirsiniz. Paging kütüphanesi, uygulamanızın ViewModel’in gözlemlenebilen bir veri yapısında tuttuğu verilerinizi gösterebilir.

Database Örnekleri

LiveData kullanarak disk belleği verilerini gözlemleme

Aşağıdaki kod parçacığı birlikte çalışan tüm parçaları gösterir. Konser etkinlikleri veritabanına eklendiğinde, kaldırıldığında veya değiştirildiğinde, RecyclerView’daki içerik otomatik ve verimli bir şekilde güncellenir.

@Dao
interface ConcertDao {
// The Int type parameter tells Room to use a PositionalDataSource
// object, with position-based loading under the hood.
@Query("SELECT * FROM concerts ORDER BY date DESC")
fun concertsByDate(): DataSource.Factory<Int, Concert>
}

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {
val concertList: LiveData<PagedList<Concert>> =
concertDao.concertsByDate().toLiveData(pageSize = 50)
}

class ConcertActivity : AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel = ViewModelProviders.of(this)
.get<ConcertViewModel>()
val recyclerView = findViewById(R.id.concert_list)
val adapter = ConcertAdapter()
viewModel.livePagedList.observe(this, PagedList(adapter::submitList))
recyclerView.setAdapter(adapter)
}
}

class ConcertAdapter() :
PagedListAdapter<Concert, ConcertViewHolder>(DIFF_CALLBACK) {
fun onBindViewHolder(holder: ConcertViewHolder, position: Int) {
val concert: Concert? = getItem(position)

// Note that "concert" is a placeholder if it's null.
holder.bindTo(concert)
}

companion object {
private val DIFF_CALLBACK = object :
DiffUtil.ItemCallback<Concert>() {
// Concert details may have changed if reloaded from the database,
// but ID is fixed.
override fun areItemsTheSame(oldConcert: Concert,
newConcert: Concert) = oldConcert.id == newConcert.id

override fun areContentsTheSame(oldConcert: Concert,
newConcert: Concert) = oldConcert == newConcert
}
}
}

RxJava2 kullanarak disk belleği verilerini gözlemleme

LiveData yerine RxJava2'yi kullanmayı tercih ederseniz, bunun yerine bir Observable veya Flowable nesnesi oluşturabilirsiniz.

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {
val concertList: Observable<PagedList<Concert>> =
concertDao.concertsByDate().toObservable(pageSize = 50)
}
class ConcertActivity : AppCompatActivity() {
private val adapter: ConcertAdapter()
private lateinit var viewModel: ConcertViewModel

private val disposable = CompositeDisposable()

public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val recyclerView = findViewById(R.id.concert_list)
viewModel = ViewModelProviders.of(this)
.get<ConcertViewModel>()
recyclerView.setAdapter(adapter)
}

override fun onStart() {
super.onStart()
disposable.add(viewModel.concertList
.subscribe(adapter::submitList)))
}

override fun onStop() {
super.onStop()
disposable.clear()
}
}

ConcertDao ve ConcertAdapter kodu, LiveData tabanlı bir çözüm için olduğu gibi RxJava2 tabanlı bir çözüm için aynıdır.

Genel yapısı itibarı ile Paging Kütüphanesini tanıdık. Diğer yazılarımda bu kütüphaneyi daha detaylı bir şekilde projeye implemente edebiliriz.

--

--