पेज वाला डेटा इकट्ठा करना

यह दस्तावेज़, पेजिंग लाइब्रेरी की खास जानकारी पर आधारित है. इसमें बताया गया है कि ऐप्लिकेशन के आर्किटेक्चर की ज़रूरतों को पूरा करने के लिए, डेटा लोड करने के समाधान को कैसे पसंद के मुताबिक बनाया जा सकता है.

ऑब्ज़र्व की जा सकने वाली सूची बनाना

आम तौर पर, आपका यूज़र इंटरफ़ेस (यूआई) कोड, LiveData<PagedList> ऑब्जेक्ट को मॉनिटर करता है. अगर RxJava2 का इस्तेमाल किया जा रहा है, तो यह Flowable<PagedList> या Observable<PagedList> ऑब्जेक्ट को मॉनिटर करता है. यह ऑब्जेक्ट, आपके ऐप्लिकेशन के ViewModel में मौजूद होता है. यह ऑब्ज़र्वेबल ऑब्जेक्ट, प्रज़ेंटेशन और आपके ऐप्लिकेशन के लिस्ट डेटा के कॉन्टेंट के बीच कनेक्शन बनाता है.

इनमें से कोई एक ऑब्ज़र्वेबल PagedList ऑब्जेक्ट बनाने के लिए, DataSource.Factory के इंस्टेंस को LivePagedListBuilder या RxPagedListBuilder ऑब्जेक्ट में पास करें. DataSource ऑब्जेक्ट, किसी एक PagedList के लिए पेज लोड करता है. फ़ैक्ट्री क्लास, कॉन्टेंट के अपडेट के जवाब में PagedList के नए इंस्टेंस बनाती है. जैसे, डेटाबेस टेबल का अमान्य होना और नेटवर्क रीफ़्रेश होना. रूम परसिस्टेंस लाइब्रेरी आपको DataSource.Factory ऑब्जेक्ट उपलब्ध करा सकती है. इसके अलावा, अपना ऑब्जेक्ट खुद भी बनाया जा सकता है.

यहां दिए गए कोड स्निपेट में, Room की DataSource.Factory-बिल्डिंग क्षमताओं का इस्तेमाल करके, आपके ऐप्लिकेशन की ViewModel क्लास में LiveData<PagedList> का नया इंस्टेंस बनाने का तरीका बताया गया है:

ConcertDao

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

ConcertViewModel

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

पेजिंग का अपना कॉन्फ़िगरेशन तय करना

बेहतर मामलों के लिए LiveData<PagedList> को और कॉन्फ़िगर करने के लिए, पेजिंग कॉन्फ़िगरेशन को भी तय किया जा सकता है. खास तौर पर, इन एट्रिब्यूट को तय किया जा सकता है:

  • पेज का साइज़: हर पेज पर मौजूद आइटम की संख्या.
  • प्रीफ़ेच डिस्टेंस: ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में दिखने वाले आखिरी आइटम के बाद, ऐसे आइटम की संख्या जिन्हें पेजिंग लाइब्रेरी को पहले से फ़ेच करने की कोशिश करनी चाहिए. यह वैल्यू, पेज के साइज़ से कई गुना ज़्यादा होनी चाहिए.
  • प्लेसहोल्डर की मौजूदगी: इससे यह तय होता है कि यूज़र इंटरफ़ेस (यूआई) में, सूची के उन आइटम के लिए प्लेसहोल्डर दिखेंगे या नहीं जो अब तक लोड नहीं हुए हैं. प्लेसहोल्डर इस्तेमाल करने के फ़ायदों और नुकसानों के बारे में जानने के लिए, अपने यूज़र इंटरफ़ेस (यूआई) में प्लेसहोल्डर उपलब्ध कराने का तरीका जानें.

अगर आपको इस बात पर ज़्यादा कंट्रोल चाहिए कि पेजिंग लाइब्रेरी आपके ऐप्लिकेशन के डेटाबेस से सूची कब लोड करे, तो LivePagedListBuilder को कस्टम Executor ऑब्जेक्ट पास करें. इसके बारे में यहां दिए गए कोड स्निपेट में बताया गया है:

ConcertViewModel

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

डेटा सोर्स का सही टाइप चुनना

यह ज़रूरी है कि आप उस डेटा सोर्स से कनेक्ट करें जो आपके सोर्स डेटा के स्ट्रक्चर को सबसे बेहतर तरीके से मैनेज करता हो:

  • अगर लोड किए जाने वाले पेजों में, 'अगला' या 'पिछला' बटन एम्बेड किया गया है, तो PageKeyedDataSource का इस्तेमाल करें. उदाहरण के लिए, अगर नेटवर्क से सोशल मीडिया पोस्ट फ़ेच की जा रही हैं, तो आपको एक लोड से दूसरे लोड में nextPage टोकन पास करना पड़ सकता है.
  • अगर आपको आइटम N+1 को फ़ेच करने के लिए, आइटम N के डेटा का इस्तेमाल करना है, तो ItemKeyedDataSource का इस्तेमाल करें. उदाहरण के लिए, अगर आपको किसी चर्चा वाले ऐप्लिकेशन के लिए थ्रेड वाली टिप्पणियां फ़ेच करनी हैं, तो आपको अगली टिप्पणी का कॉन्टेंट पाने के लिए, पिछली टिप्पणी का आईडी पास करना पड़ सकता है.
  • अगर आपको अपने डेटास्टोर में चुनी गई किसी भी जगह से डेटा के पेज फ़ेच करने हैं, तो PositionalDataSource का इस्तेमाल करें. इस क्लास की मदद से, डेटा आइटम के सेट का अनुरोध किया जा सकता है. यह सेट, आपकी चुनी गई जगह से शुरू होता है. उदाहरण के लिए, अनुरोध करने पर 1,500वीं जगह से शुरू होने वाले 50 डेटा आइटम मिल सकते हैं.

डेटा अमान्य होने पर सूचना पाना

पेजिंग लाइब्रेरी का इस्तेमाल करते समय, डेटा लेयर को आपके ऐप्लिकेशन की अन्य लेयर को यह सूचना देनी होती है कि कोई टेबल या लाइन पुरानी हो गई है. इसके लिए, अपने ऐप्लिकेशन के लिए चुनी गई DataSource क्लास से invalidate() को कॉल करें.

अपने डेटा सोर्स बनाना

अगर कस्टम लोकल डेटा सलूशन का इस्तेमाल किया जाता है या डेटा को सीधे नेटवर्क से लोड किया जाता है, तो DataSource सबक्लास में से किसी एक को लागू किया जा सकता है. यहां दिए गए कोड स्निपेट में, एक डेटा सोर्स दिखाया गया है. इसे किसी कॉन्सर्ट के शुरू होने के समय के हिसाब से सेट किया गया है:

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

इसके बाद, इस कस्टमाइज़ किए गए डेटा को PagedList ऑब्जेक्ट में लोड किया जा सकता है. इसके लिए, आपको DataSource.Factory का एक कॉन्क्रीट सबक्लास बनाना होगा. यहां दिए गए कोड स्निपेट से पता चलता है कि पिछले कोड स्निपेट में तय किए गए कस्टम डेटा सोर्स के नए इंस्टेंस कैसे जनरेट किए जाते हैं:

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

कॉन्टेंट अपडेट करने की प्रोसेस को समझना

ऑब्ज़र्व किए जा सकने वाले PagedList ऑब्जेक्ट बनाते समय, इस बात का ध्यान रखें कि कॉन्टेंट के अपडेट कैसे काम करते हैं. अगर डेटा को सीधे Room डेटाबेस से लोड किया जा रहा है, तो अपडेट आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) पर अपने-आप पुश हो जाते हैं.

पेज वाले नेटवर्क एपीआई का इस्तेमाल करते समय, आम तौर पर उपयोगकर्ता के साथ इंटरैक्शन होता है. जैसे, "रीफ़्रेश करने के लिए स्वाइप करें". यह उस DataSource को अमान्य करने के सिग्नल के तौर पर काम करता है जिसका आपने हाल ही में इस्तेमाल किया है. इसके बाद, उस डेटा सोर्स के नए इंस्टेंस का अनुरोध किया जाता है. यहां दिए गए कोड स्निपेट से इस व्यवहार के बारे में पता चलता है:

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

डेटा मैपिंग उपलब्ध कराना

पेजिंग लाइब्रेरी, DataSource से लोड किए गए आइटम के आइटम-आधारित और पेज-आधारित ट्रांसफ़ॉर्मेशन के साथ काम करती है.

यहां दिए गए कोड स्निपेट में, कॉन्सर्ट के नाम और तारीख के कॉम्बिनेशन को एक स्ट्रिंग से मैप किया गया है. इस स्ट्रिंग में, कॉन्सर्ट का नाम और तारीख, दोनों शामिल हैं:

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

यह तब काम आ सकता है, जब आपको आइटम लोड होने के बाद उन्हें रैप करना हो, कन्वर्ट करना हो या तैयार करना हो. यह काम फ़ेच एक्ज़ीक्यूटर पर किया जाता है. इसलिए, आपके पास डिस्क से डेटा पढ़ने या किसी अलग डेटाबेस से क्वेरी करने जैसे महंगे काम करने का विकल्प होता है.

सुझाव/राय दें या शिकायत करें

इन संसाधनों के ज़रिए, अपने सुझाव, शिकायत या राय और आइडिया हमारे साथ शेयर करें:

समस्या को ट्रैक करने वाला टूल
समस्याओं की शिकायत करें, ताकि हम बग ठीक कर सकें.

अन्य संसाधन

पेजिंग लाइब्रेरी के बारे में ज़्यादा जानने के लिए, यहां दिए गए संसाधन देखें.

सैंपल

कोडलैब

वीडियो