Paginarea în dezvoltarea mobilă — ce este, tipuri și principiul de funcționare

Autor: IT Sectr Publicat: 2026-03-11 Timp de citire: 9 min

Paginarea — tehnica de încărcare a datelor pe pagini, utilizată în aplicațiile mobile și serviciile web pentru lucrul cu seturi mari de înregistrări. Conform Android Developers Documentation (2025), implementarea corectă a paginării reduce încărcarea API, economisește trafic și îmbunătățește experiența utilizatorului. Încărcarea pe pagini permite aplicației să afișeze conținutul treptat, fără a aștepta încărcarea completă a tuturor datelor.

Principalele puncte

  • Paginarea — modul de încărcare a seturilor mari de date în porțiuni pentru optimizarea performanței și traficului.
  • Paginarea Offset utilizează deplasarea (page/offset) pentru navigare — metodă simplă, dar instabilă la inserări frecvente.
  • Paginarea Cursor utilizează un cursor unic din ultima înregistrare — stabilă la modificarea datelor între cereri.
  • Paginarea Keyset filtrează după coloana cu index unic — eficientă pentru tabele mari fără duplicate.
  • Paginarea Time-based grupează înregistrările după marcajele de timp — convenabilă pentru fluxuri de știri și rețele sociale.

Ce este paginarea?

Paginarea (din engl. pagination — divizare în pagini) — este tehnica de împărțire a unui set mare de date în porțiuni succesive (pagini). În aplicațiile mobile, paginarea este utilizată la încărcarea listelor de mesaje, fluxurilor de știri, cataloagelor de produse, istoricului comenzilor și oricăror alte colecții cu un număr potențial nelimitat de înregistrări.

Fără paginare, aplicația este nevoită să încarce toate datele deodată, ceea ce duce la așteptări lungi, consum mare de trafic și funcționare instabilă pe dispozitivele slabe. Cererea API cu paginare returnează doar o porțiune de date și meta-informații pentru încărcarea următoarei — astfel, aplicația controlează volumul de informații primite.

Principalii indicatori ai paginării: dimensiunea paginii (page size) — numărul de înregistrări pe o pagină (de obicei 10-50), și numărul paginii sau cursorul — indicatorul poziției curente în set. Alegerea dimensiunii paginii depinde de tipul datelor: pentru elemente compacte (denumiri) sunt suficiente 20-30, pentru carduri cu imagini — 10-15.

De ce este necesară paginarea în aplicațiile mobile

Dispozitivele mobile au resurse limitate: volumul memoriei RAM, viteza procesorului și limitele de trafic. Paginarea rezolvă trei sarcini cheie: reducerea consumului de memorie (în memorie se păstrează doar elementele vizibile), accelerarea primei afișări (prima porțiune se încarcă mai repede decât întregul set) și economisirea traficului (datele se încarcă doar când utilizatorul derulează lista).

Principalele tipuri de paginare

Există patru tipuri principale de paginare, fiecare rezolvând sarcini specifice. Alegerea metodei depinde de cerințele privind coerența datelor, arhitectura API, tipul de stocare și complexitatea admisibilă a implementării pe client și server.

TipPrincipiul de funcționareStabilitateViteza la volume mari
OffsetLIMIT + OFFSET în SQLscăzutăscade odată cu creșterea OFFSET
CursorWHERE id > last_idridicatăstabilă (O(log n))
KeysetWHERE key > last_keyridicatăstabilă (O(log n))
Time-basedWHERE created_at < last_timemediestabilă cu index

Când să folosești fiecare tip

Paginarea Offset este potrivită pentru seturi de date statice sau rareori actualizate, când implementarea simplă este importantă. Cursor și Keyset — pentru date dinamice cu inserări frecvente. Time-based — pentru fluxuri cronologice, unde înregistrările sunt ordonate după momentul creării. Standardul GraphQL Relay utilizează paginarea cursor ca singura metodă recomandată.

Paginarea Offset: avantaje și dezavantaje

Paginarea Offset — cel mai simplu tip de încărcare pe pagini. Clientul transmite parametrii page și limit (sau offset și limit), serverul aplică SQL OFFSET și LIMIT. De exemplu, page=2, limit=20 va returna înregistrările 21-40. Această metodă este intuitivă și ușor de implementat pe orice stivă tehnologică.

python
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items")
async def get_items(
    page: int = Query(default=1, ge=1),
    limit: int = Query(default=20, le=100)
):
    offset = (page - 1) * limit
    items = await fetch_items(offset, limit)
    total = await count_items()
    return {
        "items": items,
        "total": total,
        "page": page,
        "pages": (total + limit - 1) // limit
    }

Problema incoerenței datelor

Principalul dezavantaj al paginării Offset — problema înregistrărilor omise și duplicate. Dacă între două cereri se adaugă înregistrări noi în tabel, OFFSET se deplasează: utilizatorul poate vedea aceeași înregistrare de două ori sau poate rata una nouă. Acest lucru este critic pentru fluxurile de știri și chat-uri, unde coerența este importantă.

O altă problemă — scăderea performanței la OFFSET-uri mari. Baza de date trebuie să scaneze și să sară peste primele offset înregistrări înainte de a returna rezultatul. La offset=100000 chiar și cu LIMIT 20, serverul va petrece timp considerabil scanând. PostgreSQL și MySQL demonstrează o scădere liniară a vitezei odată cu creșterea OFFSET.

Când Offset este încă o alegere bună

Paginarea Offset rămâne cea mai bună alegere pentru: panouri administrative (datele se schimbă rar, este necesară navigarea între pagini), rapoarte și jurnale istorice (secțiune fixă de date), cataloage cu filtrare (se poate naviga la orice pagină). Offset este, de asemenea, cel mai ușor de implementat pe client — RecyclerView cu Paging 3 îl suportă implicit.

Paginarea Keyset și Time-based

Paginarea Keyset utilizează o cheie unică (de obicei cheia primară) pentru filtrarea înregistrărilor. În loc de OFFSET, cererea folosește WHERE id > last_seen_id. Aceasta asigură o performanță stabilă indiferent de numărul de înregistrări și absența duplicatelor la inserări, deoarece înregistrările noi au întotdeauna un id mai mare.

sql
-- Paginare Offset (problematică)
SELECT * FROM posts
ORDER BY id
LIMIT 20 OFFSET 100;

-- Paginare Keyset (stabilă)
SELECT * FROM posts
WHERE id > 100
ORDER BY id
LIMIT 20;

Paginarea Time-based

Paginarea Time-based (sau cursorul temporal) utilizează marcajul de timp created_at pentru navigare. Clientul trimite timestamp-ul ultimei înregistrări încărcate, serverul returnează înregistrările create înainte sau după acest marcaj. Metoda este populară în rețelele sociale și fluxurile de știri, unde ordinea înregistrărilor este determinată de momentul publicării.

Particularitatea paginării Time-based — posibile duplicate dacă două înregistrări sunt create în aceeași milisecundă. Pentru a elimina această problemă, se combină cheia time-based cu id-ul unic: WHERE (created_at, id) < (last_time, last_id). Un astfel de cursor compus garantează unicitatea fiecărei înregistrări și ordinea exactă.

Comparația Keyset și Time-based

Paginarea Keyset necesită o coloană cu o valoare unică și monoton crescătoare (id auto-incrementat, UUID v7). Time-based este potrivită pentru orice tabel cu created_at, dar necesită procesarea suplimentară a duplicatelor. Diferența principală: Keyset funcționează stabil la orice operații de inserare, iar Time-based este sensibilă la marcaje de timp identice.

Cum să alegi tipul de paginare pentru proiect

Alegerea tipului de paginare depinde de natura datelor și de cerințele privind experiența utilizatorului. Mai jos sunt recomandări pentru scenarii tipice în dezvoltarea mobilă. Nu există o soluție universală — fiecare metodă are un domeniu de aplicare în care este optimă.

  • Chat / mesagerie — Paginarea Cursor (după id-ul mesajului). Mesajele noi se adaugă de sus, cursorul nu se deplasează.
  • Flux de știri — Paginarea Time-based (după created_at). Înregistrările sunt ordonate cronologic, cronologia este importantă.
  • Catalog de produse — Paginarea Offset. Utilizatorul poate naviga la o pagină specifică, datele se schimbă rar.
  • Istoric comenzi — Paginarea Cursor. Stabilitatea este importantă, deoarece comenzile noi se adaugă între încărcări.
  • Comentarii — Paginarea Keyset. Fiecare comentariu are un id unic, volume mari fără duplicate.

Implementarea pe Android cu Paging 3

Biblioteca Android Paging 3 suportă toate tipurile de paginare prin PagingSource. Pentru Offset — PagingSource cu cheie Int (page), pentru Cursor — cu cheie String sau Long (cursor). PagingSource gestionează automat încărcarea, cache-ul și reîncercările la erori.

kotlin
class PostPagingSource(
    private val api: PostApi
) : PagingSource<Long, Post>() {

    override suspend fun load(
        params: LoadParams<Long>
    ): LoadResult<Long, Post> {
        val cursor = params.key ?: Long.MAX_VALUE
        return try {
            val response = api.getPosts(cursor, params.loadSize)
            LoadResult.Page(
                data = response.items,
                prevKey = null,
                nextKey = response.items.lastOrNull()?.id
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<Long, Post>): Long? {
        return state.anchorPosition?.let {
            state.closestItemToPosition(it)?.id
        }
    }
}

Recomandări privind dimensiunea paginii

Dimensiunea paginii influențează viteza de încărcare și percepția performanței. Pentru aplicațiile mobile, intervalul optim este 10-25 de elemente pe pagină. Mai puțin de 10 — cereri prea frecvente la API și derulare sacadată. Mai mult de 25 — încărcarea lungă a primei porțiuni pe rețele lente.

Pentru imagini și video, dimensiunea paginii se reduce la 5-10, deoarece fiecare element necesită timp suplimentar pentru încărcarea media. Pentru liste cu elemente text (comentarii, jurnale), dimensiunea poate fi mărită la 30-50 de înregistrări. Se recomandă ca dimensiunea paginii să fie configurabilă prin API, astfel încât clientul să se poată adapta la diferite condiții de rețea.

Întrebări frecvente

Ce este paginarea în cuvinte simple?

Paginarea — încărcarea datelor în porțiuni, nu pe toate deodată. Ca într-o carte: citești o pagină, apoi treci la următoarea. În aplicație, aceasta înseamnă că la derularea listei se încarcă următoarea porțiune de date, nu întreaga listă deodată, ceea ce economisește trafic și memorie.

Cu ce se deosebește Offset de Cursor în paginare?

Offset numără înregistrările: „sari peste 20, returnează următoarele 10„. Dacă între încărcări se adaugă o înregistrare nouă — numerotarea se deplasează. Cursor utilizează identificatorul unic al ultimei înregistrări: „returnează 10 înregistrări după ID = 100„. Înregistrările noi nu afectează poziția.

Care este dimensiunea optimă a paginii de paginare?

Pentru aplicațiile mobile, optim este 10-25 de elemente. Pentru liste cu imagini — 5-10, pentru fluxuri text — 20-30. Dimensiunea depinde de dimensiunea medie a unui element: cu cât elementul este mai greu, cu atât pagina trebuie să fie mai mică pentru o afișare rapidă.

Cum se implementează paginarea în RecyclerView?

Utilizați biblioteca Paging 3 din Android Jetpack. Aceasta oferă PagingSource pentru încărcare, PagingData pentru flux reactiv și PagingDataAdapter pentru încărcarea automată la derulare. Biblioteca suportă paginarea Offset, Cursor și Keyset prin PagingSource personalizat.

Ce este derularea infinită și cu ce se deosebește de paginare?

Derularea infinită — un model UI în care o nouă porțiune de date se încarcă automat la apropierea de sfârșitul listei. Paginarea — este mecanismul de încărcare a datelor în porțiuni, iar derularea infinită este una dintre modalitățile de afișare a acesteia. Alternativa — butonul „Încarcă mai mult„.

Rezumat

  • Paginarea — tehnica de încărcare a datelor în porțiuni, necesară pentru aplicațiile mobile cu orice tip de liste.
  • Paginarea Offset este simplă în implementare, dar suferă de incoerență la inserări și scădere a performanței la OFFSET-uri mari.
  • Paginarea Cursor utilizează un identificator unic pentru navigare — stabilă și eficientă la orice volume.
  • Paginarea Keyset filtrează după cheia primară, asigurând performanță maximă prin utilizarea indicilor.
  • Paginarea Time-based grupează înregistrările după marcajele de timp — ideală pentru fluxuri cronologice și rețele sociale.
  • Alegerea metodei depinde de natura datelor: pentru dinamice — Cursor/Keyset, pentru statice — Offset, pentru fluxuri — Time-based.
  • Paging 3 pe Android și soluțiile standard cursor pe iOS/web oferă infrastructură gata pentru orice tip de paginare.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și