Saltar al contenido
CrossFly es 100% open sourceSíguenos en GitHub
CrossFlyCrossFly
Empezar

Esta página fue traducida automáticamente del portugués y puede contener errores. La versión en portugués es la canónica.

PagedDataAdapter

PagedDataAdapter es un DataAdapter paginado para VirtualListView, con un caché LRU de páginas. Mantiene solo algunas páginas en memoria; al desplazarse a una región cuya página fue descartada, muestra un spinner y recarga asincrónicamente vía loadPage.

Es una clase abstracta: tú implementas getTotalCount, loadPage, createView y bindItem. La traducción índice→página, el caché, el spinner y el bloqueo de scroll durante la carga ya vienen listos.

🔴 · Paquete: dev.crossfly.ui · Implementa: VirtualListView.DataAdapter · Uso: pasado al constructor de VirtualListView

Cuándo usar

  • Datos que vienen de red/base de datos en páginas y no caben todos en memoria.
  • Quieres caché automático (LRU) con recarga transparente al volver a una región antigua.

Cuándo NO usar

  • Todos los datos ya están en memoria → implementa DataAdapter directamente en el VirtualListView.
  • Lista pequeña → ListView.

Ejemplo completo (copiar, pegar y ejecutar)

package com.exemplo;

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

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: 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 ítems/página, 5 páginas
         public int getTotalCount() { return total; }
         public void loadPage(int pageIndex, PageCallback cb) {
            // Simula una carga (reemplace por llamada de red/base en background).
            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);   // las listas usan LAY_FILL (absorben la altura)
   }
}

Los fragmentos de abajo muestran solo el núcleo (lo que va dentro de onShow()). Para ejecutar, colócalos en el esqueleto MainWindow de arriba.

Uso básico

PagedDataAdapter adapter = new PagedDataAdapter(20, 5) { // 20 ítems/página, 5 páginas en memoria
   public int getTotalCount() { return serverTotal; }
   public void loadPage(int pageIndex, PageCallback cb) {
      api.fetch(pageIndex, data -> cb.onPageLoaded(pageIndex, data)); // puede ser background
   }
   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);

Constructores

Constructor Descripción
PagedDataAdapter(int pageSize, int maxCachedPages) pageSize: ítems por página. maxCachedPages: páginas mantenidas en memoria (LRU)

Ambos campos son public final. La VirtualListView se inyecta a sí misma en el adapter cuando pasas este adapter a su constructor.

Métodos abstractos a implementar

Método Descripción
int getTotalCount() Total de ítems en el servidor (usado por getCount())
void loadPage(int pageIndex, PageCallback callback) Carga una página asíncrona; llama a callback.onPageLoaded(pageIndex, items) al terminar (desde cualquier thread)
Component createView() throws Exception Crea una view en blanco
void bindItem(Component view, Object item, int index) throws Exception Vincula el ítem crudo (Object) a la view — haz el cast a tu tipo

Propiedades y métodos útiles

Método Tipo Qué hace
isAvailable(int index) boolean Si el ítem ya está en el caché
clearCache() void Vacía caché y estado de carga
getCount() int Delega a getTotalCount()

Funcionamiento (resumen)

  • bindView(view, index) traduce pageIndex = index / pageSize e itemInPage = index % pageSize.
    • Página en el caché → bindItem inmediato (waitingForData = false).
    • Página ausente → waitingForData = true y dispara requestPage(pageIndex).
  • requestPage evita solicitudes duplicadas (loading), muestra spinner y pausa el fling; al volver el callback, marshala a la thread de UI con Component.onUI(...), graba la página, oculta el spinner, fuerza el re-bind de la franja (invalidateRange) y reanuda el fling.
  • El cache es un LinkedHashMap en modo access-order que descarta la página más antigua (LRU) cuando excede maxCachedPages.

Callbacks y eventos

Callback Cuándo se dispara
PageCallback.onPageLoaded(int pageIndex, Object[] items) Tú lo llamas al terminar de cargar la página (desde cualquier thread)

Estados

  • waitingForData — true mientras alguna página carga; señala a la VirtualListView que bloquee el scroll.
  • LRU — las páginas antiguas se descartan; al desplazarse de vuelta, se recargan (nuevo spinner + solicitud).

Ejemplo — cast de ítem tipado

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;            // cast del Object crudo
      ((Label) view).setText(c.getNome());
   }
};
VirtualListView list = new VirtualListView(Relative.ofFont(2.4f), adapter);

Buenas prácticas

  • Los ítems de la página llegan como Object[] — haz el cast del item a tu tipo en bindItem.
  • No llames a APIs de UI dentro de loadPage antes del callback — el adapter ya cambia a la thread de UI internamente al recibir onPageLoaded.
  • Ajusta maxCachedPages al patrón de desplazamiento: un caché mayor evita recargas al volver, a costa de memoria.

Errores comunes

  • Llamar a onPageLoaded con el pageIndex equivocado — el adapter usa ese índice para grabar en el caché e invalidar la franja correcta.
  • Bloquear en loadPage — debe ser asíncrono; la thread de UI no puede esperar a la red.

Ver también

¿Te resultó útil esta página?