יישום פגינציה של נתונים באפליקציות מובייל: Cursor לעומת Offset

כאשר אפליקציה ניידת טוענת אלפי רשומות בבקשה אחת, המשתמשים חווים הקפאות ומסך לבן. אנו מיישמים פאג'ינציה ברמת ה-API כדי לשמור על ניווט חלק גם כשהנתונים גדלים. הצוות שלנו מספק את הפרויקט במפתח מלא—מבחירת האסטרטגיה ועד אינטגרציה ותמיכה מתמשכת.

פיתוח ותמיכה בכל סוגי היישומים הניידים:

יישומים ניידים למידע ובידור
אפליקציות חדשות, משחקים, מדריכים, קטלוגים מקוונים, אפליקציות מזג אוויר, אפליקציות כושר ובריאות, אפליקציות נסיעות, אפליקציות חינוכיות, רשתות חברתיות ומסנג'רים, חידונים, בלוגים ופודקאסטים, פורומים, אגרגטורים
יישומים ניידים למסחר אלקטרוני
חנויות מקוונות, אפליקציות B2B, מרקטפלייסים, בורסות מקוונות, שירותי קאשבק, בורסות, פלטפורמות דרופשיפינג, תוכניות נאמנות, משלוחי מזון ומוצרים, מערכות תשלום.
יישומים ניידים לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, ניהול פרויקטים, כלים לצוותי מכירות, ניהול פיננסי, ניהול ייצור, ניהול לוגיסטיקה ומשלוחים, ניהול משאבי אנוש, מערכות ניטור נתונים
יישומים ניידים לשירותים אלקטרוניים
פלטפורמות מודעות מסווגות, בתי ספר מקוונים, בתי קולנוע מקוונים, פלטפורמות שירות אלקטרוניות, פלטפורמות קאשבק, אירוח וידאו, פורטלים נושאיים, פלטפורמות הזמנות ותזמון מקוונות, פלטפורמות מסחר מקוונות

אלה הם רק חלק מסוגי היישומים הניידים שאנו עובדים איתם, ולכל אחד מהם עשויים להיות מאפיינים ופונקציונליות ספציפיים משלו, המותאמים לצרכים ולמטרות הספציפיות של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 1734 השירותים
יישום פגינציה של נתונים באפליקציות מובייל: Cursor לעומת Offset
בינוני
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית מובייל עבור FEEDME
    פיתוח אפליקציית מובייל עבור FEEDME
    971
  • פיתוח אפליקציית מובייל עבור XOOMER
    פיתוח אפליקציית מובייל עבור XOOMER
    869
  • פיתוח אפליקציית מובייל עבור RHL
    פיתוח אפליקציית מובייל עבור RHL
    1289
  • פיתוח אפליקציית מובייל עבור ZIPPY
    פיתוח אפליקציית מובייל עבור ZIPPY
    1143
  • פיתוח אפליקציית מובייל עבור Affhome
    פיתוח אפליקציית מובייל עבור Affhome
    1076
  • פיתוח אפליקציית מובייל עבור חברת FLAVORS
    פיתוח אפליקציית מובייל עבור חברת FLAVORS
    677

בקשת רשימה של 10,000 מוצרים בקריאה אחת היא טעות קלאסית שהמהנדסים שלנו רואים בכל פרויקט שלישי. ה-API מחזיר 40 MB של JSON, האפליקציה קופאת בזמן הניתוח, והמשתמש רואה מסך לבן למשך 8 שניות—ואז עוזב. אנו מיישמים פגינציה ברמת החוזה בין הלקוח לשרת: זה מפחית עומס פי 3–5 ומספק ניווט חלק ללא עיכובים. בדקו את הפגינציה של ה-API שלכם—צרו קשר לצורך ביקורת.

יישום פגינציה: Offset או Cursor?

רוב המפתחים פונים כברירת מחדל לפגינציית offset: ?page=2&limit=20. זה עובד כל עוד הנתונים סטטיים. אבל הוסיפו פיד חי שבו רשומות מוכנסות בראש, והמשתמש בעמוד 3 מפספס רשומות או רואה כפילויות: INSERT בתחילת הרשימה מזיז את כל ה-offsets. בטבלאות עם 500,000+ שורות, offset סורק עד 100,000 שורות כדי להזיז את הסמן—שאילתות לוקחות 200–400 ms.

פגינציה מבוססת cursor פותרת זאת: השרת מחזיר next_cursor, הלקוח מעביר אותו בבקשה הבאה. ה-cursor הוא טוקן אטום (בדרך כלל base64 של id + timestamp) שמקבע את המיקום במערך הנתונים. שרתי PostgreSQL מיישמים זאת עם WHERE id < :cursor ORDER BY id DESC LIMIT 20. אין כפילויות, אין פערים. מהירויות השאילתות נשארות יציבות—50–100 ms ללא קשר לגודל הטבלה.

קריטריון פגינציית Offset פגינציית Cursor
פשטות היישום גבוהה בינונית (דורש cursor בשרת)
כפילויות/פערים בעת הוספה כן לא
ביצועים על טבלאות גדולות מתדרדרים (O(N)) יציבים (O(1))
תמיכה בקפיצה לעמוד שרירותי כן (page=3) קשה (רק גלילה רציפה)
שמירה במטמון קלה (עמודים לפי offset) דורשת אחסון cursors

למה פגינציית Cursor יעילה יותר מ-Offset?

פגינציית cursor מהירה פי 3 מ-offset על טבלאות מ-100,000 שורות—בדיקות ביצועים מראות ירידה בזמן התגובה מ-300 ms ל-90 ms. היא גם מבטיחה עקביות נתונים תחת הוספות במקביל. עבור פידי חדשות, הודעות צ'אט וקטלוגים שמתעדכנים תדיר, זו הבחירה המחייבת.

איך להגדיר מטמון עם RemoteMediator?

באנדרואיד עם Paging 3, פגינציית cursor מיושמת דרך RemoteMediator + PagingSource:

class ItemPagingSource(
    private val api: ItemsApi,
    private val query: String
) : PagingSource<String, Item>() {
    override suspend fun load(params: LoadParams<String>): LoadResult<String, Item> {
        return try {
            val response = api.getItems(
                cursor = params.key,
                limit = params.loadSize,
                query = query
            )
            LoadResult.Page(
                data = response.items,
                prevKey = null,
                nextKey = response.nextCursor
            )
        } catch (e: HttpException) {
            LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<String, Item>): String? {
        return state.anchorPosition?.let { anchor ->
            state.closestPageToPosition(anchor)?.nextKey
        }
    }
}

class ItemPagingSource( private val api: ItemsApi, private val query: String ) : PagingSource<String, Item>() { override suspend fun load(params: LoadParams<String>): LoadResult<String, Item> { return try { val response = api.getItems( cursor = params.key, limit = params.loadSize, query = query ) LoadResult.Page( data = response.items, prevKey = null, nextKey = response.nextCursor ) } catch (e: HttpException) { LoadResult.Error(e) } } override fun getRefreshKey(state: PagingState<String, Item>): String? { return state.anchorPosition?.let { anchor -> state.closestPageToPosition(anchor)?.nextKey } } } ב-Compose מתחבר דרך LazyColumn—binding מוכן שמטפל במצבי collectAsLazyPagingItems(), Loading, Error ללא קוד נוסף.

ב-iOS, המקבילה היא פריסה קומפוזיציונית עם NotLoading ו-UICollectionViewDiffableDataSource. טעינה מוקדמת מיושמת דרך NSDiffableDataSourceSnapshot: המתודה UICollectionViewDataSourcePrefetching נקראת N תאים לפני הקצה, ומפעילה בקשה לרשת מראש. ללא טעינה מוקדמת, במהירויות גלילה מעל 500 px/s, מופיעים תאים ריקים—המשתמש ממתין 1–2 שניות לטעינה.

איך ליישם פגינציית Cursor באנדרואיד: שלב אחר שלב

  1. הגדירו את חוזה ה-API: השרת מחזיר prefetchItemsAt בתגובת ה-JSON.
  2. צרו next_cursor שמעביר את ה-cursor ב-PagingSource<String, Item>.
  3. חברו loadParams.key למטמון לא מקוון: RemoteMediator מביא נתונים מהרשת ושומר אותם ב-Room.
  4. ב-RemoteMediator, יישמו PagingSource כדי לשחזר מיקום לאחר רענון.
  5. הגדירו getRefreshKey עם LazyColumn ו-collectAsLazyPagingItems() מפורש עם כפתור ניסיון חוזר.

השוואת אסטרטגיות מטמון: RemoteMediator לעומת מטמון פשוט

פרמטר RemoteMediator + Room מטמון פשוט (LruCache)
גישה לא מקוונת כן לא
עקביות בעדכונים ETag/Last-Modified אין מנגנון
מורכבות היישום בינונית נמוכה
חיסכון בתעבורה 60–80% 0%
המלצה פרויקטים בעומס גבוה אבות טיפוס, נתונים סטטיים

גלילה אינסופית ו-Pull-to-Refresh

גלילה אינסופית ללא מצב שגיאה היא בעיה אופיינית. הרשת נופלת בעמוד 5, הבקשה נתקעת, המשתמש גולל למטה וכלום לא קורה. יש צורך ב-LoadStateFooter מפורש עם כפתור ניסיון חוזר.

ב-Paging 3:

adapter.addLoadStateListener { loadState ->
    binding.retryButton.isVisible = loadState.source.append is LoadState.Error
    binding.progressBar.isVisible = loadState.source.append is LoadState.Loading
}

Pull-to-refresh מאפס את הפגינציה לעמוד הראשון דרך LoadStateFooter—Paging 3 מבטל את adapter.addLoadStateListener { loadState -> binding.retryButton.isVisible = loadState.source.append is LoadState.Error binding.progressBar.isVisible = loadState.source.append is LoadState.Loading } ומתחיל מחדש. ב-SwiftUI, זה ה-modifier adapter.refresh() שקורא ל-PagingSource ב-TCA או מעדכן את ה-view model refreshable.

מטמון ומצב לא מקוון

Paging 3 + Room הוא השילוב הסטנדרטי של offline-first. invalidateQueries() כותב נתונים למסד הנתונים המקומי, @StateObject קורא מ-Room במקום מהרשת. המשתמש רואה נתונים גם ללא אינטרנט; נתונים חדשים נטענים ברקע.

נקודה מרכזית: אסטרטגיית ביטול המטמון. אם השרת מעדכן רשומה, העותק המקומי הופך למיושן. פתרון: RemoteMediator או PagingSource בכותבי התגובה—הלקוח שולח ETag, השרת מחזיר 304 ללא גוף אם אין שינוי. Room מעדכן רק רשומות שהשתנו דרך Last-Modified. זה מפחית את כמות הנתונים שמועברת ב-60–80%.

מה כלול בעבודה

  • ביקורת על ה-API הנוכחי ומפרט חוזה הפגינציה.
  • יישום פגינציית cursor/offset בצד הלקוח (אנדרואיד/iOS/קרוס-פלטפורמה).
  • אינטגרציה של RemoteMediator ו-Room למצב לא מקוון.
  • הגדרת טעינה מוקדמת ולוגיקת ניסיון חוזר.
  • בדיקות על מכשירים אמיתיים עם סימולציית רשת חלשה.
  • תיעוד קוד והמלצות לשיפור השרת.
  • תמיכה לאחר היישום: שבועיים של ייעוץ.

לוחות זמנים

פגינציית offset פשוטה ללא מטמון—1–2 ימים. פגינציית cursor עם RemoteMediator, מטמון לא מקוון ולוגיקת ניסיון חוזר—3–5 ימים. העלות מחושבת באופן אישי לאחר ניתוח הדרישות וה-API הקיים. יש לנו ניסיון של 5+ שנים בפיתוח מובייל ומעל 30 פרויקטים עם פגינציה—סמכו על המומחים שלנו. הזמינו ביקורת פגינציה לאפליקציה שלכם—נמצא את הפתרון האופטימלי.

טעויות נפוצות ביישום פגינציה

  • חוסר טעינה מוקדמת ב-iOS—תאים ריקים בגלילה מהירה.
  • שימוש ב-offset בפידים עם הוספות תכופות—כפילויות ופערים.
  • התעלמות ממצבי טעינה ושגיאה: המשתמש לא רואה אינדיקטור.
  • אין מטמון—כל גלילה מפעילה בקשה לרשת.
  • גודל עמוד שגוי: 5 פריטים גורם לטעינות תכופות, 100 גורם להמתנה ארוכה.