# PagedDataAdapter

> VirtualListView के लिए पेजिनेटेड DataAdapter, पेजों के LRU कैश और असिंक्रोनस लोडिंग के साथ।

Source: https://crossfly.dev/hi/docs/ui/widgets/paged-data-adapter — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# PagedDataAdapter

`PagedDataAdapter` [`VirtualListView`](/docs/ui/widgets/virtuallistview) के लिए एक **पेजिनेटेड** `DataAdapter` है, जिसमें **पेजों का LRU कैश** है। यह मेमोरी में केवल कुछ पेज रखता है; जब आप ऐसे क्षेत्र में स्क्रॉल करते हैं जिसका पेज हटा दिया गया था, तो यह एक स्पिनर दिखाता है और `loadPage` के माध्यम से असिंक्रोनस रूप से पुनः लोड करता है।

यह एक **अमूर्त** क्लास है: आप `getTotalCount`, `loadPage`, `createView` और `bindItem` लागू करते हैं। इंडेक्स→पेज अनुवाद, कैश, स्पिनर और लोडिंग के दौरान स्क्रॉल लॉक पहले से ही तैयार आते हैं।

> 🔴 · **पैकेज:** `dev.crossfly.ui` · **लागू करता है:** `VirtualListView.DataAdapter` · **उपयोग:** `VirtualListView` के कंस्ट्रक्टर को पास किया जाता है

## कब उपयोग करें
- डेटा जो नेटवर्क/डेटाबेस से **पेजों** में आता है और सब मेमोरी में नहीं समाता।
- आप किसी पुराने क्षेत्र में लौटने पर पारदर्शी पुनः लोडिंग के साथ स्वचालित कैश (LRU) चाहते हैं।

## कब उपयोग न करें
- सारा डेटा पहले से ही मेमोरी में है → [`VirtualListView`](/docs/ui/widgets/virtuallistview) पर सीधे `DataAdapter` लागू करें।
- छोटी सूची → [`ListView`](/docs/ui/widgets/listview)।

## पूरा उदाहरण (कॉपी करें, पेस्ट करें और चलाएं)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.graphics.*;   // Relative

/** चलाने योग्य मुख्य स्क्रीन। launcher (classname) की ओर संकेत करें और चलाएँ: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      final int pageSize = 20;
      final int total    = 10_000;

      PagedDataAdapter adapter = new PagedDataAdapter(pageSize, 5) { // 20 आइटम/पेज, 5 पेज
         public int getTotalCount() { return total; }
         public void loadPage(int pageIndex, PageCallback cb) {
            // एक लोडिंग का अनुकरण करता है (बैकग्राउंड में नेटवर्क/डेटाबेस कॉल से बदलें)।
            Object[] data = new Object[pageSize];
            for (int i = 0; i < pageSize; i++)
               data[i] = "Item " + (pageIndex * pageSize + i);
            cb.onPageLoaded(pageIndex, data);
         }
         public Component createView() { return new Label(""); }
         public void bindItem(Component view, Object item, int index) {
            ((Label) view).setText(item.toString());
         }
      };

      VirtualListView list = new VirtualListView(Relative.ofFont(2f), adapter);

      add(LAY_FILL, list);   // सूचियां LAY_FILL उपयोग करती हैं (ऊंचाई अवशोषित करती हैं)
   }
}
```

> नीचे दिए गए स्निपेट **केवल मुख्य भाग** दिखाते हैं (जो `onShow()` के अंदर जाता है)। चलाने के लिए, उन्हें ऊपर के `MainWindow` ढांचे में रखें।

## बुनियादी उपयोग
```java
PagedDataAdapter adapter = new PagedDataAdapter(20, 5) { // 20 आइटम/पेज, मेमोरी में 5 पेज
   public int getTotalCount() { return serverTotal; }
   public void loadPage(int pageIndex, PageCallback cb) {
      api.fetch(pageIndex, data -> cb.onPageLoaded(pageIndex, data)); // बैकग्राउंड हो सकता है
   }
   public Component createView() { return new Label(""); }
   public void bindItem(Component view, Object item, int index) {
      ((Label) view).setText(item.toString());
   }
};
VirtualListView list = new VirtualListView(Relative.ofFont(2f), adapter);
layout.add(LAY_FILL, list);
```

## कंस्ट्रक्टर
| कंस्ट्रक्टर | विवरण |
|---|---|
| `PagedDataAdapter(int pageSize, int maxCachedPages)` | `pageSize`: प्रति पेज आइटम। `maxCachedPages`: मेमोरी में रखे गए पेज (LRU) |

दोनों फ़ील्ड `public final` हैं। जब आप इस adapter को इसके कंस्ट्रक्टर को पास करते हैं, तो `VirtualListView` स्वयं को adapter में इंजेक्ट कर लेता है।

## लागू करने के लिए अमूर्त मेथड
| मेथड | विवरण |
|---|---|
| `int getTotalCount()` | सर्वर पर आइटम की कुल संख्या (`getCount()` द्वारा उपयोग किया जाता है) |
| `void loadPage(int pageIndex, PageCallback callback)` | एक पेज असिंक्रोनस रूप से लोड करता है; समाप्त होने पर `callback.onPageLoaded(pageIndex, items)` कॉल करें (किसी भी थ्रेड से) |
| `Component createView() throws Exception` | एक खाली view बनाता है |
| `void bindItem(Component view, Object item, int index) throws Exception` | कच्चे आइटम (`Object`) को view से जोड़ता है — अपने प्रकार में कास्ट करें |

## उपयोगी प्रॉपर्टीज़ और मेथड
| मेथड | प्रकार | क्या करता है |
|---|---|---|
| `isAvailable(int index)` | `boolean` | क्या आइटम पहले से कैश में है |
| `clearCache()` | `void` | कैश और लोडिंग स्थिति को शून्य करता है |
| `getCount()` | `int` | `getTotalCount()` को डेलिगेट करता है |

## कार्यप्रणाली (सारांश)
- `bindView(view, index)` `pageIndex = index / pageSize` और `itemInPage = index % pageSize` का अनुवाद करता है।
  - पेज कैश में → तुरंत `bindItem` (`waitingForData = false`)।
  - पेज अनुपस्थित → `waitingForData = true` और `requestPage(pageIndex)` ट्रिगर करता है।
- `requestPage` डुप्लिकेट अनुरोधों से बचता है (`loading`), स्पिनर दिखाता है और **fling को रोकता है**; कॉलबैक लौटने पर, `Component.onUI(...)` के साथ UI थ्रेड पर मार्शल करता है, पेज लिखता है, स्पिनर छिपाता है, रेंज की पुनः-बाइंडिंग को बाध्य करता है (`invalidateRange`) और **fling को फिर से शुरू करता है**।
- `cache` एक access-order मोड में `LinkedHashMap` है जो `maxCachedPages` से अधिक होने पर सबसे पुराने पेज (LRU) को हटा देता है।

## कॉलबैक और इवेंट
| कॉलबैक | कब ट्रिगर होता है |
|---|---|
| `PageCallback.onPageLoaded(int pageIndex, Object[] items)` | पेज लोड करना समाप्त होने पर आप कॉल करते हैं (किसी भी थ्रेड से) |

## स्थितियां
- **`waitingForData`** — जब तक कोई पेज लोड हो रहा है, `true`; `VirtualListView` को **स्क्रॉल लॉक करने** का संकेत देता है।
- **LRU** — पुराने पेज हटा दिए जाते हैं; वापस स्क्रॉल करने पर, वे पुनः लोड किए जाते हैं (नया स्पिनर + अनुरोध)।

## उदाहरण — टाइप किए गए आइटम का कास्ट
```java
PagedDataAdapter adapter = new PagedDataAdapter(50, 4) {
   public int getTotalCount() { return repo.total(); }
   public void loadPage(int page, PageCallback cb) {
      repo.loadAsync(page, 50, lista -> cb.onPageLoaded(page, lista.toArray()));
   }
   public Component createView() { return new Label(""); }
   public void bindItem(Component view, Object item, int index) {
      Cliente c = (Cliente) item;            // कच्चे Object का cast
      ((Label) view).setText(c.getNome());
   }
};
VirtualListView list = new VirtualListView(Relative.ofFont(2.4f), adapter);
```

## सर्वोत्तम अभ्यास
- पेज के आइटम `Object[]` के रूप में आते हैं — `bindItem` में `item` को अपने प्रकार में कास्ट करें।
- कॉलबैक से पहले `loadPage` के अंदर UI API को **कॉल न करें** — `onPageLoaded` प्राप्त होने पर adapter पहले से ही आंतरिक रूप से UI थ्रेड पर स्विच कर लेता है।
- स्क्रॉलिंग पैटर्न के अनुसार `maxCachedPages` समायोजित करें: बड़ा कैश वापस लौटने पर पुनः लोडिंग से बचाता है, मेमोरी की कीमत पर।

## सामान्य गलतियां
- **गलत `pageIndex` के साथ `onPageLoaded` कॉल करना** — adapter इस इंडेक्स का उपयोग कैश में लिखने और सही रेंज को invalidate करने के लिए करता है।
- **`loadPage` में ब्लॉक करना** — यह असिंक्रोनस होना चाहिए; UI थ्रेड नेटवर्क का इंतज़ार नहीं कर सकता।

## यह भी देखें
- क्षेत्र गाइड: [`ui/`](/docs/ui) · रेसिपी: [`cookbook/`](/docs/cookbook)
- संबंधित कंपोनेंट: [`VirtualListView`](/docs/ui/widgets/virtuallistview)
