Paging 2 लाइब्रेरी के बारे में खास जानकारी   Android Jetpack का हिस्सा.

पेजिंग लाइब्रेरी की मदद से, डेटा के छोटे-छोटे हिस्सों को एक बार में लोड और दिखाया जा सकता है. मांग के हिसाब से कुछ डेटा लोड करने से, नेटवर्क बैंडविड्थ और सिस्टम के संसाधनों का इस्तेमाल कम होता है.

इस गाइड में, लाइब्रेरी के कई उदाहरण दिए गए हैं. साथ ही, इसके काम करने के तरीके के बारे में खास जानकारी दी गई है. यह लाइब्रेरी कैसे काम करती है, इसके पूरे उदाहरण देखने के लिए, अन्य संसाधन सेक्शन में जाकर, कोडलैब और सैंपल आज़माएं.

सेटअप

अपने Android ऐप्लिकेशन में पेजिंग कॉम्पोनेंट इंपोर्ट करने के लिए, अपने ऐप्लिकेशन की build.gradle फ़ाइल में ये डिपेंडेंसी जोड़ें:

Groovy

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
}

लाइब्रेरी आर्किटेक्चर

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

PagedList

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

यहां दिए गए कोड स्निपेट में, PagedList ऑब्जेक्ट के LiveData होल्डर का इस्तेमाल करके, डेटा लोड करने और उसे दिखाने के लिए, ऐप्लिकेशन के व्यू मॉडल को कॉन्फ़िगर करने का तरीका बताया गया है:

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

डेटा

PagedList का हर इंस्टेंस, उससे जुड़े DataSource ऑब्जेक्ट से आपके ऐप्लिकेशन के डेटा का अप-टू-डेट स्नैपशॉट लोड करता है. डेटा, आपके ऐप्लिकेशन के बैकएंड या डेटाबेस से PagedList ऑब्जेक्ट में फ़्लो होता है.

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

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 ऑब्जेक्ट में डेटा लोड करने के तरीके के बारे में ज़्यादा जानने के लिए, पेज पर मौजूद डेटा लोड करने के तरीके के बारे में गाइड देखें.

यूज़र इंटरफ़ेस (यूआई)

PagedList क्लास, PagedListAdapter के साथ काम करती है, ताकि आइटम को RecyclerView में लोड किया जा सके. ये क्लास, कॉन्टेंट लोड होने पर उसे फ़ेच करने और दिखाने के लिए साथ मिलकर काम करती हैं. साथ ही, स्क्रीन पर न दिखने वाले कॉन्टेंट को पहले से फ़ेच करती हैं और कॉन्टेंट में होने वाले बदलावों को ऐनिमेट करती हैं.

ज़्यादा जानने के लिए, पेज वाली सूचियां दिखाने के तरीके के बारे में गाइड देखें.

अलग-अलग डेटा आर्किटेक्चर के साथ काम करना

पेजिंग लाइब्रेरी में ये डेटा आर्किटेक्चर काम करते हैं:

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

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

पेजिंग लाइब्रेरी के साथ काम करने वाले आर्किटेक्चर में डेटा फ़्लो
पहली इमेज. पेजिंग लाइब्रेरी के साथ काम करने वाले हर आर्किटेक्चर में डेटा कैसे फ़्लो करता है.

इस सेक्शन के बाकी हिस्से में, डेटा फ़्लो के इस्तेमाल के हर उदाहरण को कॉन्फ़िगर करने के सुझाव दिए गए हैं.

सिर्फ़ नेटवर्क

बैकएंड सर्वर से डेटा दिखाने के लिए, Retrofit API के सिंक्रोनस वर्शन का इस्तेमाल करें. इससे आपके कस्टम DataSource ऑब्जेक्ट में जानकारी लोड की जा सकेगी.

सिर्फ़ डेटाबेस

लोकल स्टोरेज को मॉनिटर करने के लिए, अपना RecyclerView सेट अप करें. इसके लिए, रूम परसिस्टेंस लाइब्रेरी का इस्तेमाल करें. इस तरह, जब भी आपके ऐप्लिकेशन के डेटाबेस में डेटा डाला जाता है या उसमें बदलाव किया जाता है, तो ये बदलाव उस RecyclerView में अपने-आप दिखने लगते हैं जो इस डेटा को दिखा रहा है.

नेटवर्क और डेटाबेस

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

नेटवर्क की गड़बड़ियां ठीक करना

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

  • ऐसा हो सकता है कि कोई सर्वर, नेटवर्क के अनुरोध का जवाब न दे पाए.
  • ऐसा हो सकता है कि डिवाइस किसी धीमे या कमज़ोर नेटवर्क से कनेक्ट हो.

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

अपने मौजूदा ऐप्लिकेशन को अपडेट करना

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

कस्टम पेजिंग सलूशन

अगर आपके ऐप्लिकेशन के डेटा सोर्स से डेटा के छोटे सबसेट लोड करने के लिए, कस्टम फ़ंक्शन का इस्तेमाल किया जाता है, तो इस लॉजिक को PagedList क्लास के लॉजिक से बदला जा सकता है. PagedList के इंस्टेंस, सामान्य डेटा सोर्स के लिए पहले से मौजूद कनेक्शन उपलब्ध कराते हैं. ये इंस्टेंस, RecyclerView ऑब्जेक्ट के लिए अडैप्टर भी उपलब्ध कराते हैं. इन्हें आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में शामिल किया जा सकता है.

पेजों के बजाय सूचियों का इस्तेमाल करके डेटा लोड किया गया

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

CursorAdapter का इस्तेमाल करके, डेटा कर्सर को सूची वाले व्यू से जोड़ना

आपका ऐप्लिकेशन, Cursor के डेटा को ListView से जोड़ने के लिए, CursorAdapter का इस्तेमाल कर सकता है. ऐसे में, आपको आम तौर पर अपने ऐप्लिकेशन के सूची वाले यूज़र इंटरफ़ेस (यूआई) कंटेनर के तौर पर, ListView से RecyclerView पर माइग्रेट करना होगा. इसके बाद, Cursor कॉम्पोनेंट को Room या PositionalDataSource से बदलना होगा. यह इस बात पर निर्भर करता है कि Cursor के इंस्टेंस, SQLite डेटाबेस को ऐक्सेस करते हैं या नहीं.

कुछ मामलों में, जैसे कि Spinner के इंस्टेंस के साथ काम करते समय, आपको सिर्फ़ अडैप्टर देना होता है. इसके बाद, लाइब्रेरी उस अडैप्टर में लोड किए गए डेटा को लेती है और आपको डेटा दिखाती है. इन स्थितियों में, अपने अडैप्टर के डेटा के टाइप को LiveData<PagedList> में बदलें. इसके बाद, इस सूची को ArrayAdapter ऑब्जेक्ट में रैप करें. इसके बाद ही, लाइब्रेरी क्लास को यूज़र इंटरफ़ेस (यूआई) में इन आइटम को इनफ़्लेट करने की अनुमति दें.

AsyncListUtil का इस्तेमाल करके, कॉन्टेंट को एसिंक्रोनस तरीके से लोड करना

अगर जानकारी के ग्रुप को एसिंक्रोनस तरीके से लोड और दिखाने के लिए, AsyncListUtil ऑब्जेक्ट का इस्तेमाल किया जा रहा है, तो पेजिंग लाइब्रेरी डेटा लोड करने की प्रोसेस को आसान बनाती है:

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

डेटाबेस के उदाहरण

यहां दिए गए कोड स्निपेट में, सभी हिस्सों को एक साथ काम करने के कई संभावित तरीके दिखाए गए हैं.

LiveData का इस्तेमाल करके, पेज पर मौजूद डेटा को मॉनिटर करना

यहां दिए गए कोड स्निपेट में, सभी कॉम्पोनेंट एक साथ काम करते हुए दिखते हैं. डेटाबेस में कॉन्सर्ट इवेंट जोड़े जाने, हटाए जाने या उनमें बदलाव किए जाने पर, RecyclerView में मौजूद कॉन्टेंट अपने-आप और बेहतर तरीके से अपडेट हो जाता है:

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 का इस्तेमाल करके, पेज पर मौजूद डेटा को मॉनिटर करना

अगर आपको LiveData के बजाय RxJava2 का इस्तेमाल करना है, तो Observable या Flowable ऑब्जेक्ट बनाएं:

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

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

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 और ConcertAdapter के लिए कोड, RxJava2 पर आधारित समाधान के लिए वैसा ही होता है जैसा कि LiveData पर आधारित समाधान के लिए होता है.

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

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

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

अन्य संसाधन

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

सैंपल

कोडलैब

वीडियो