Sayfalara ayrılmış verileri toplama

Bu kılavuz, çağrı kitaplığına genel bakış ile ilgili temel bilgileri vererek uygulamanızın veri yükleme çözümünü uygulamanızın mimari gereksinimlerini karşılamak için nasıl özelleştirebileceğinizi açıklar.

Gözlemlenebilir liste oluşturma

Genellikle kullanıcı arayüzü kodunuzda uygulamanızın ViewModel bölümünde bulunan bir LiveData<PagedList> nesnesi (veya RxJava2 kullanıyorsanız Flowable<PagedList> ya da Observable<PagedList> nesnesi) gözlemlenir. Bu gözlemlenebilir nesne, uygulamanızın liste verilerinin sunumu ile içerikleri arasında bir bağlantı oluşturur.

Bu gözlemlenebilir PagedList nesnelerinden birini oluşturmak için bir DataSource.Factory örneğini LivePagedListBuilder veya RxPagedListBuilder nesnesine geçirin. DataSource nesnesi, tek bir PagedList için sayfaları yükler. Fabrika sınıfı, içerik güncellemelerine yanıt olarak veritabanı tablosu geçersiz kılmaları ve ağ yenilemeleri gibi yeni PagedList örnekleri oluşturur. Oda kalıcı kitaplığı sizin için DataSource.Factory nesne sağlayabilir veya kendi nesnenizi oluşturabilirsiniz.

Aşağıdaki kod snippet'i, Room'un DataSource.Factory oluşturma özelliklerini kullanarak uygulamanızın ViewModel sınıfında yeni bir LiveData<PagedList> örneğini nasıl oluşturacağınızı göstermektedir:

KonserDao

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

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();
}

Konser GörünümüModeli

Kotlin

// The Int type argument corresponds to a PositionalDataSource object.
val myConcertDataSource : DataSource.Factory<Int, Concert> =
       concertDao.concertsByDate()

val concertList = myConcertDataSource.toLiveData(pageSize = 50)

Java

// The Integer type argument corresponds to a PositionalDataSource object.
DataSource.Factory<Integer, Concert> myConcertDataSource =
       concertDao.concertsByDate();

LiveData<PagedList<Concert>> concertList =
        LivePagedListBuilder(myConcertDataSource, /* page size */ 50).build();

Kendi sayfa oluşturma yapılandırmanızı tanımlama

Gelişmiş destek kayıtları için bir LiveData<PagedList>'ı daha da yapılandırmak amacıyla kendi sayfa oluşturma yapılandırmanızı da tanımlayabilirsiniz. Özellikle, aşağıdaki özellikleri tanımlayabilirsiniz:

  • Sayfa boyutu: Her sayfadaki öğe sayısıdır.
  • Önceden getirme mesafesi: Bir uygulamanın kullanıcı arayüzündeki son görünür öğe göz önünde bulundurulduğunda, Sayfalama Kitaplığı'nın bu son öğeden sonraki öğeleri önceden getirmeye çalışması gereken öğe sayısı. Bu değer, sayfa boyutundan birkaç kat daha büyük olmalıdır.
  • Yer tutucu varlığı: Kullanıcı arayüzünün, yüklenmesi henüz tamamlanmamış liste öğelerine ilişkin yer tutucuları görüntüleyip görüntülemeyeceğini belirler. Yer tutucu kullanmanın avantajları ve dezavantajları hakkında bir tartışma için Kullanıcı arayüzünüzde yer tutucu sağlama'yı öğrenin.

Sayfalama Kitaplığı'nın, uygulamanızın veritabanından ne zaman liste yüklediği üzerinde daha fazla kontrole sahip olmak istiyorsanız LivePagedListBuilder'e aşağıdaki kod snippet'inde gösterildiği gibi özel bir Executor nesnesi iletin:

Konser GörünümüModeli

Kotlin

val myPagingConfig = Config(
        pageSize = 50,
        prefetchDistance = 150,
        enablePlaceholders = true
)

// The Int type argument corresponds to a PositionalDataSource object.
val myConcertDataSource : DataSource.Factory<Int, Concert> =
        concertDao.concertsByDate()

val concertList = myConcertDataSource.toLiveData(
        pagingConfig = myPagingConfig,
        fetchExecutor = myExecutor
)

Java

PagedList.Config myPagingConfig = new PagedList.Config.Builder()
        .setPageSize(50)
        .setPrefetchDistance(150)
        .setEnablePlaceholders(true)
        .build();

// The Integer type argument corresponds to a PositionalDataSource object.
DataSource.Factory<Integer, Concert> myConcertDataSource =
        concertDao.concertsByDate();

LiveData<PagedList<Concert>> concertList =
        new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig)
            .setFetchExecutor(myExecutor)
            .build();

Doğru veri kaynağı türünü seçme

Kaynak verilerinizin yapısını en iyi şekilde işleyen veri kaynağına bağlanmanız önemlidir:

  • Yüklediğiniz sayfalar sonraki/önceki anahtarlarını yerleştiriyorsa PageKeyedDataSource seçeneğini kullanın. Örneğin, ağdan sosyal medya yayınları alıyorsanız bir yüklemeden sonraki yüklemeye bir nextPage jetonu iletmeniz gerekebilir.
  • N+1 öğesini getirmek için N öğesindeki verileri kullanmanız gerekiyorsa ItemKeyedDataSource değerini kullanın. Örneğin, bir tartışma uygulaması için mesaj dizili yorumlar alıyorsanız bir sonraki yorumun içeriğini almak için son yorumun kimliğini iletmeniz gerekebilir.
  • Veri mağazanızda seçtiğiniz herhangi bir konumdan veri sayfaları getirmeniz gerekiyorsa PositionalDataSource kullanın. Bu sınıf, seçtiğiniz konumdan başlayarak bir veri öğesi grubu istemeyi destekler. Örneğin, istek, konum 1500 ile başlayan 50 veri öğesini döndürebilir.

Veriler geçersiz olduğunda bildir

Sayfalama Kitaplığı'nı kullanırken, bir tablo veya satır eskidiğinde uygulamanızın diğer katmanlarına bunu bildirmek veri katmanına bağlıdır. Bunu yapmak üzere uygulamanız için seçtiğiniz DataSource sınıfından invalidate() numaralı telefonu arayın.

Kendi veri kaynaklarınızı oluşturun

Özel bir yerel veri çözümü kullanıyorsanız veya verileri doğrudan bir ağdan yüklüyorsanız DataSource alt sınıflarından birini uygulayabilirsiniz. Aşağıdaki kod snippet'i, belirli bir konserin başlangıç zamanına eklenmiş bir veri kaynağını gösterir:

Kotlin

class ConcertTimeDataSource() :
        ItemKeyedDataSource<Date, Concert>() {
    override fun getKey(item: Concert) = item.startTime

    override fun loadInitial(
            params: LoadInitialParams<Date>,
            callback: LoadInitialCallback<Concert>) {
        val items = fetchItems(params.requestedInitialKey,
                params.requestedLoadSize)
        callback.onResult(items)
    }

    override fun loadAfter(
            params: LoadParams<Date>,
            callback: LoadCallback<Concert>) {
        val items = fetchItemsAfter(
            date = params.key,
            limit = params.requestedLoadSize)
        callback.onResult(items)
    }
}

Java

public class ConcertTimeDataSource
        extends ItemKeyedDataSource<Date, Concert> {
    @NonNull
    @Override
    public Date getKey(@NonNull Concert item) {
        return item.getStartTime();
    }

    @Override
    public void loadInitial(@NonNull LoadInitialParams<Date> params,
            @NonNull LoadInitialCallback<Concert> callback) {
        List<Concert> items =
            fetchItems(params.key, params.requestedLoadSize);
        callback.onResult(items);
    }

    @Override
    public void loadAfter(@NonNull LoadParams<Date> params,
            @NonNull LoadCallback<Concert> callback) {
        List<Concert> items =
            fetchItemsAfter(params.key, params.requestedLoadSize);
        callback.onResult(items);
    }

Daha sonra, somut bir DataSource.Factory alt sınıfı oluşturarak bu özelleştirilmiş verileri PagedList nesnelerine yükleyebilirsiniz. Aşağıdaki kod snippet'i, önceki kod snippet'inde tanımlanan özel veri kaynağının yeni örneklerinin nasıl oluşturulacağını gösterir:

Kotlin

class ConcertTimeDataSourceFactory :
        DataSource.Factory<Date, Concert>() {
    val sourceLiveData = MutableLiveData<ConcertTimeDataSource>()
    var latestSource: ConcertDataSource?
    override fun create(): DataSource<Date, Concert> {
        latestSource = ConcertTimeDataSource()
        sourceLiveData.postValue(latestSource)
        return latestSource
    }
}

Java

public class ConcertTimeDataSourceFactory
        extends DataSource.Factory<Date, Concert> {
    private MutableLiveData<ConcertTimeDataSource> sourceLiveData =
            new MutableLiveData<>();

    private ConcertDataSource latestSource;

    @Override
    public DataSource<Date, Concert> create() {
        latestSource = new ConcertTimeDataSource();
        sourceLiveData.postValue(latestSource);
        return latestSource;
    }
}

İçerik güncellemelerinin işleyiş şeklini göz önünde bulundurun

Gözlemlenebilir PagedList nesneleri oluştururken içerik güncellemelerinin işleyiş şeklini göz önünde bulundurun. Doğrudan bir Oda veritabanı'ndan veri yüklüyorsanız güncellemeler otomatik olarak uygulamanızın kullanıcı arayüzüne aktarılır.

Sayfalı ağ API'si kullanırken genellikle "yenilemek için kaydırın" gibi bir kullanıcı etkileşiminiz vardır. Bu, en son kullandığınız DataSource'in geçersiz kılınması için bir sinyal olarak kullanılır. Ardından bu veri kaynağının yeni bir örneğini istersiniz. Aşağıdaki kod snippet'i bu davranışı göstermektedir:

Kotlin

class ConcertActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        concertTimeViewModel.refreshState.observe(this, Observer {
            // Shows one possible way of triggering a refresh operation.
            swipeRefreshLayout.isRefreshing =
                    it == MyNetworkState.LOADING
        })
        swipeRefreshLayout.setOnRefreshListener {
            concertTimeViewModel.invalidateDataSource()
        }
    }
}

class ConcertTimeViewModel(firstConcertStartTime: Date) : ViewModel() {
    val dataSourceFactory = ConcertTimeDataSourceFactory(firstConcertStartTime)
    val concertList: LiveData<PagedList<Concert>> =
            dataSourceFactory.toLiveData(
                pageSize = 50,
                fetchExecutor = myExecutor
            )

    fun invalidateDataSource() =
            dataSourceFactory.sourceLiveData.value?.invalidate()
}

Java

public class ConcertActivity extends AppCompatActivity {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        // ...
        viewModel.getRefreshState()
                .observe(this, new Observer<NetworkState>() {
            // Shows one possible way of triggering a refresh operation.
            @Override
            public void onChanged(@Nullable MyNetworkState networkState) {
                swipeRefreshLayout.isRefreshing =
                        networkState == MyNetworkState.LOADING;
            }
        };

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshListener() {
            @Override
            public void onRefresh() {
                viewModel.invalidateDataSource();
            }
        });
    }
}

public class ConcertTimeViewModel extends ViewModel {
    private LiveData<PagedList<Concert>> concertList;
    private DataSource<Date, Concert> mostRecentDataSource;

    public ConcertTimeViewModel(Date firstConcertStartTime) {
        ConcertTimeDataSourceFactory dataSourceFactory =
                new ConcertTimeDataSourceFactory(firstConcertStartTime);
        mostRecentDataSource = dataSourceFactory.create();
        concertList = new LivePagedListBuilder<>(dataSourceFactory, 50)
                .setFetchExecutor(myExecutor)
                .build();
    }

    public void invalidateDataSource() {
        mostRecentDataSource.invalidate();
    }
}

Veri eşleme sağlama

Sayfalandırma Kitaplığı, DataSource tarafından yüklenen öğelerin öğe tabanlı ve sayfa tabanlı dönüşümlerini destekler.

Aşağıdaki kod snippet'inde konser adı ve konser tarihinin bir kombinasyonu, hem adı hem de tarihi içeren tek bir dizeyle eşlenir:

Kotlin

class ConcertViewModel : ViewModel() {
    val concertDescriptions : LiveData<PagedList<String>>
        init {
            val concerts = database.allConcertsFactory()
                    .map { "${it.name} - ${it.date}" }
                    .toLiveData(pageSize = 50)
        }
}

Java

public class ConcertViewModel extends ViewModel {
    private LiveData<PagedList<String>> concertDescriptions;

    public ConcertViewModel(MyDatabase database) {
        DataSource.Factory<Integer, Concert> factory =
                database.allConcertsFactory().map(concert ->
                    concert.getName() + "-" + concert.getDate());
        concertDescriptions = new LivePagedListBuilder<>(
            factory, /* page size */ 50).build();
    }
}

Bu işlem, öğeleri yüklendikten sonra sarmalamak, dönüştürmek veya hazırlamak istiyorsanız yararlı olabilir. Bu iş getirme yürütücüsinde yapıldığından diskten okuma veya ayrı bir veritabanını sorgulama gibi potansiyel olarak pahalı işler yapabilirsiniz.

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