Sayfa 2 kitaplığına genel bakış Android Jetpack'in bir parçasıdır.

Sayfalama Kitaplığı, aynı anda küçük veri parçalarını yüklemenize ve görüntülemenize yardımcı olur. İsteğe bağlı verilerin bir kısmını yüklemek, ağ bant genişliği ve sistem kaynaklarının kullanımını azaltır.

Bu kılavuzda, kütüphane hakkında çeşitli kavramsal örnekler ve kitaplığın nasıl çalıştığına dair genel bir bakış sunulmaktadır. Bu kitaplığın nasıl çalıştığına dair eksiksiz örnekleri görmek için codelab'i ve ek kaynaklar bölümündeki örnekleri deneyin.

Kurulum

Sayfalama bileşenlerini Android uygulamanıza aktarmak için aşağıdaki bağımlılıkları uygulamanızın build.gradle dosyasına ekleyin:

Modern

dependencies {
  def paging_version = "2.1.2"

  implementation "androidx.paging:paging-runtime:$paging_version" // For Kotlin use paging-runtime-ktx

  // alternatively - without Android dependencies for testing
  testImplementation "androidx.paging:paging-common:$paging_version" // For Kotlin use paging-common-ktx

  // optional - RxJava support
  implementation "androidx.paging:paging-rxjava2:$paging_version" // For Kotlin use paging-rxjava2-ktx
}

Kotlin

dependencies {
  val paging_version = "2.1.2"

  implementation("androidx.paging:paging-runtime:$paging_version") // For Kotlin use paging-runtime-ktx

  // alternatively - without Android dependencies for testing
  testImplementation("androidx.paging:paging-common:$paging_version") // For Kotlin use paging-common-ktx

  // optional - RxJava support
  implementation("androidx.paging:paging-rxjava2:$paging_version") // For Kotlin use paging-rxjava2-ktx
}

Kütüphane mimarisi

Bu bölümde sayfa oluşturma kitaplığının ana bileşenleri açıklanır ve gösterilmektedir.

Sayfalı Liste

Sayfalandırma Kitaplığı'nın temel bileşeni, uygulama verilerinizin veya sayfaların parçalarını yükleyen PagedList sınıfıdır. Daha fazla veri gerektikçe bu veriler mevcut PagedList nesnesine sayfalandırılır. Yüklenen herhangi bir veri değişirse LiveData veya RxJava2 tabanlı bir nesneden gözlemlenebilir veri sahibine yeni bir PagedList örneği gönderilir. PagedList nesneleri oluşturulduğunda uygulamanızın kullanıcı arayüzü, bu nesneleri gösterirken kullanıcı arayüzü denetleyicilerinizin yaşam döngüsüne de uygun hareket eder.

Aşağıdaki kod snippet'i, uygulamanızın görüntüleme modelini, PagedList nesnelerinden oluşan bir LiveData tutucuyu kullanarak veri yüklemek ve sunmak için nasıl yapılandırabileceğinizi gösterir:

Kotlin

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

Java

public class ConcertViewModel extends ViewModel {
    private ConcertDao concertDao;
    public final LiveData<PagedList<Concert>> concertList;

    // Creates a PagedList object with 50 items per page.
    public ConcertViewModel(ConcertDao concertDao) {
        this.concertDao = concertDao;
        concertList = new LivePagedListBuilder<>(
                concertDao.concertsByDate(), 50).build();
    }
}

Veri

Her PagedList örneği, karşılık gelen DataSource nesnesinden uygulama verilerinizin güncel bir anlık görüntüsünü yükler. Uygulamanızın arka ucundan veya veritabanından PagedList nesnesine veri akışı olur.

Aşağıdaki örnekte, uygulamanızın verilerini düzenlemek için Oda kalıcı kitaplığı kullanılmıştır ancak verilerinizi başka bir yöntemle depolamak istiyorsanız kendi veri kaynağı fabrikanızı da sağlayabilirsiniz.

Kotlin

@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>
}

Java

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

PagedList nesnelerine nasıl veri yükleyebileceğiniz hakkında daha fazla bilgi edinmek için Sayfa verilen verileri yükleme ile ilgili kılavuza bakın.

Kullanıcı Arayüzü

PagedList sınıfı, öğeleri RecyclerView klasörüne yüklemek için bir PagedListAdapter ile birlikte çalışır. Bu sınıflar, yüklenen içeriği getirmek ve görüntülemek, görüntü dışı içeriği önceden getirmek ve içerik değişikliklerini canlandırmak için birlikte çalışır.

Daha fazla bilgi edinmek için Sayfalı listeleri görüntüleme kılavuzuna bakın.

Farklı veri mimarilerini destekleme

Sayfalama Kitaplığı aşağıdaki veri mimarilerini destekler:

  • Yalnızca arka uç sunucusundan sunulur.
  • Yalnızca cihaz üzerindeki bir veritabanında depolanır.
  • Cihaz üzerindeki veritabanını önbellek olarak kullanan diğer kaynakların kombinasyonu.

Şekil 1'de bu mimari senaryolarının her birinde veri akışı gösterilmektedir. Yalnızca ağ veya yalnızca veritabanı çözümü durumunda veriler doğrudan uygulamanızın kullanıcı arayüzü modeline aktarılır. Birleşik bir yaklaşım kullanıyorsanız veriler arka uç sunucunuzdan cihaz üzerindeki bir veritabanına ve daha sonra uygulamanızın kullanıcı arayüzü modeline akar. Bazen, her veri akışının uç noktasında yüklenecek veri kalmaz. Bu noktada veri sağlayan bileşenden daha fazla veri istenir. Örneğin, bir cihaz üzerindeki veritabanında veri kalmadığında sunucudan daha fazla veri ister.

Veri akışı diyagramları
Şekil 1. Sayfalama Kitaplığı'nın desteklediği mimarilerin her biri üzerinden veri akışı nasıl gerçekleştirilir?

Bu bölümün geri kalanında, her bir veri akışı kullanım alanının yapılandırılmasına ilişkin öneriler verilmiştir.

Yalnızca ağ

Bir arka uç sunucusundan alınan verileri görüntülemek için Retrofit API'nin eşzamanlı sürümünü kullanarak bilgileri kendi özel DataSource nesnenize yükleyin.

Yalnızca veritabanı

Tercihen Oda kalıcı kitaplığını kullanarak yerel depolama alanını gözlemlemek için RecyclerView cihazınızı ayarlayın. Böylece, uygulamanızın veritabanına her veri eklendiğinde veya mevcut veritabanında her değişiklik yapıldığında, söz konusu değişiklikler bu verileri gösteren RecyclerView öğesine otomatik olarak yansıtılır.

Ağ ve veritabanı

Veritabanını gözlemlemeye başladıktan sonra, PagedList.BoundaryCallback kullanarak veritabanında veri kalmadığında dinleme yapabilirsiniz. Daha sonra ağınızdan daha fazla öğe getirebilir ve bunları veritabanına ekleyebilirsiniz. Kullanıcı arayüzünüz veritabanını gözlemliyorsa tek yapmanız gereken budur.

Ağ hatalarını işleme

Çağrı Kitaplığı'nı kullanarak görüntülemekte olduğunuz verileri getirmek veya sayfalamak için bir ağ kullanırken, birçok bağlantı kesintili veya kesintili olduğundan, ağı her zaman "kullanılabilir" veya "kullanılamıyor" şeklinde değerlendirmemek önemlidir:

  • Belirli bir sunucu, ağ isteğine yanıt vermeyebilir.
  • Cihaz yavaş veya zayıf bir ağa bağlı olabilir.

Bunun yerine, uygulamanız hata olup olmadığını kontrol etmeli ve ağın kullanılamadığı durumlarda mümkün olduğunca sorunsuz bir şekilde kurtarma yapmalıdır. Örneğin, kullanıcılara veri yenileme adımının işe yaramazsa seçmeleri için bir "yeniden dene" düğmesi sağlayabilirsiniz. Veri sayfalama adımında bir hata oluşursa sayfalama isteklerini otomatik olarak yeniden denemek en iyisidir.

Mevcut uygulamanızı güncelleyin

Uygulamanız zaten bir veritabanından veya arka uç kaynağından veri kullanıyorsa Sayfalama Kitaplığı'nın sağladığı işlevlere doğrudan yükseltme yapmak mümkündür. Bu bölümde, ortak bir mevcut tasarıma sahip bir uygulamanın nasıl yeni sürüme geçirileceği gösterilmektedir.

Özel sayfalama çözümleri

Uygulamanızın veri kaynağından küçük veri alt kümelerini yüklemek için özel işlev kullanıyorsanız bu mantığı PagedList sınıfındaki mantıkla değiştirebilirsiniz. PagedList örnekleri, yaygın veri kaynaklarına yerleşik bağlantılar sunar. Bu örnekler, uygulamanızın kullanıcı arayüzüne ekleyebileceğiniz RecyclerView nesneleri için de bağdaştırıcılar sağlar.

Sayfalar yerine listeler kullanılarak yüklenen veriler

Kullanıcı arayüzünüzün bağdaştırıcısı için yedekleme veri yapısı olarak bellek içi liste kullanıyorsanız listedeki öğelerin sayısı fazlalaşabiliyorsa PagedList sınıfı kullanarak veri güncellemelerini gözlemlemeyi düşünün. PagedList örnekleri, veri güncellemelerini uygulamanızın kullanıcı arayüzüne iletmek için LiveData<PagedList> veya Observable<List> kullanarak yükleme sürelerini ve bellek kullanımını en aza indirir. Daha da iyisi, uygulamanızda bir List nesnesini PagedList nesnesiyle değiştirmek, uygulamanızın kullanıcı arayüzü yapısında veya veri güncelleme mantığında herhangi bir değişiklik gerektirmez.

CursorAdapter'ı kullanarak bir veri imlecini liste görünümüyle ilişkilendirme

Uygulamanız, Cursor aracındaki verileri bir ListView ile ilişkilendirmek için CursorAdapter kullanabilir. Bu durumda, genellikle uygulamanızın liste kullanıcı arayüzü kapsayıcısı olarak bir ListView öğesinden RecyclerView öğesine geçmeniz ve ardından Cursor örneklerinin SQLite veritabanına erişip erişemediğine bağlı olarak Cursor bileşenini Room veyaPositionalDataSource ile değiştirmeniz gerekir.

Bazı durumlarda (örneğin, Spinner örnekleriyle çalışırken yalnızca adaptörün kendisini sağlarsınız). Daha sonra bir kitaplık, bu bağdaştırıcıya yüklenen verileri alır ve verileri sizin için görüntüler. Bu tür durumlarda, bağdaştırıcınızın veri türünü LiveData<PagedList> olarak değiştirin ve ardından bir kitaplık sınıfının kullanıcı arayüzünde bu öğeleri genişletmesini denemeden önce bu listeyi bir ArrayAdapter nesnesinin içine alın.

AsyncListUtil kullanarak içeriği eşzamansız olarak yükleme

Bilgi gruplarını eşzamansız olarak yüklemek ve görüntülemek için AsyncListUtil nesnelerini kullanıyorsanız Sayfalandırma Kitaplığı, verileri daha kolay yüklemenize olanak tanır:

  • Verilerinizin konum odaklı olması gerekmez. Sayfalama Kitaplığı, ağın sağladığı anahtarları kullanarak verileri doğrudan arka ucunuzdan yüklemenize olanak tanır.
  • Verileriniz sayılamayacak kadar büyük olabilir. Sayfalama Kitaplığı'nı kullanarak, hiç veri kalmayana kadar sayfalara veri yükleyebilirsiniz.
  • Verilerinizi daha kolay gözlemleyebilirsiniz. Sayfalama kitaplığı, uygulamanızın ViewModelinin gözlemlenebilir bir veri yapısında tuttuğu verilerinizi sunabilir.

Veritabanı örnekleri

Aşağıdaki kod snippet'leri, tüm parçaların birlikte çalışmasını sağlamanın birkaç olası yolunu göstermektedir.

LiveData kullanarak sayfalandırılmış verileri gözlemleme

Aşağıdaki kod snippet'i, tüm parçaların birlikte çalışmasını gösterir. Konser etkinlikleri veritabanına eklendiğinde, kaldırıldığında veya veritabanında değiştirildikçe RecyclerView'daki içerik de otomatik ve etkili bir şekilde güncellenir:

Kotlin

@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)
        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        val viewModel: ConcertViewModel by viewModels()
        val recyclerView = findViewById(R.id.concert_list)
        val adapter = ConcertAdapter()
        viewModel.concertList.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
        }
    }
}

Java

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

public class ConcertViewModel extends ViewModel {
    private ConcertDao concertDao;
    public final LiveData<PagedList<Concert>> concertList;

    public ConcertViewModel(ConcertDao concertDao) {
        this.concertDao = concertDao;
        concertList = new LivePagedListBuilder<>(
            concertDao.concertsByDate(), /* page size */ 50).build();
    }
}

public class ConcertActivity extends AppCompatActivity {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ConcertViewModel viewModel =
                new ViewModelProvider(this).get(ConcertViewModel.class);
        RecyclerView recyclerView = findViewById(R.id.concert_list);
        ConcertAdapter adapter = new ConcertAdapter();
        viewModel.concertList.observe(this, adapter::submitList);
        recyclerView.setAdapter(adapter);
    }
}

public class ConcertAdapter
        extends PagedListAdapter<Concert, ConcertViewHolder> {
    protected ConcertAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public void onBindViewHolder(@NonNull ConcertViewHolder holder,
            int position) {
        Concert concert = getItem(position);
        if (concert != null) {
            holder.bindTo(concert);
        } else {
            // Null defines a placeholder item - PagedListAdapter automatically
            // invalidates this row when the actual object is loaded from the
            // database.
            holder.clear();
        }
    }

    private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<Concert>() {
        // Concert details may have changed if reloaded from the database,
        // but ID is fixed.
        @Override
        public boolean areItemsTheSame(Concert oldConcert, Concert newConcert) {
            return oldConcert.getId() == newConcert.getId();
        }

        @Override
        public boolean areContentsTheSame(Concert oldConcert,
                Concert newConcert) {
            return oldConcert.equals(newConcert);
        }
    };
}

RxJava2 kullanarak sayfalandırılmış verileri gözlemleme

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

Kotlin

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

Java

public class ConcertViewModel extends ViewModel {
    private ConcertDao concertDao;
    public final Observable<PagedList<Concert>> concertList;

    public ConcertViewModel(ConcertDao concertDao) {
        this.concertDao = concertDao;

        concertList = new RxPagedListBuilder<>(
                concertDao.concertsByDate(), /* page size */ 50)
                        .buildObservable();
    }
}

Daha sonra aşağıdaki snippet'teki kodu kullanarak verileri gözlemlemeyi başlatabilir ve durdurabilirsiniz:

Kotlin

class ConcertActivity : AppCompatActivity() {
    private val adapter = ConcertAdapter()

    // Use the 'by viewModels()' Kotlin property delegate
    // from the activity-ktx artifact
    private val viewModel: ConcertViewModel by viewModels()

    private val disposable = CompositeDisposable()

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val recyclerView = findViewById(R.id.concert_list)
        recyclerView.setAdapter(adapter)
    }

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

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

Java

public class ConcertActivity extends AppCompatActivity {
    private ConcertAdapter adapter = new ConcertAdapter();
    private ConcertViewModel viewModel;

    private CompositeDisposable disposable = new CompositeDisposable();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        RecyclerView recyclerView = findViewById(R.id.concert_list);

        viewModel = new ViewModelProvider(this).get(ConcertViewModel.class);
        recyclerView.setAdapter(adapter);
    }

    @Override
    protected void onStart() {
        super.onStart();
        disposable.add(viewModel.concertList
                .subscribe(adapter.submitList(flowableList)
        ));
    }

    @Override
    protected void onStop() {
        super.onStop();
        disposable.clear();
    }
}

ConcertDao ve ConcertAdapter kodu, LiveData tabanlı çözümlerle RxJava2 tabanlı çözümlerin kodu aynıdır.

Geri bildirim gönderme

Aşağıdaki kaynakları kullanarak geri bildirimlerinizi ve fikirlerinizi bizimle paylaşabilirsiniz:

Sorun izleyici
Hataları düzeltebilmemiz için sorunları bildirin.

Ek kaynaklar

Sayfalama Kitaplığı hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.

Sana Özel

Codelab uygulamaları

Videolar