מחזור החיים ב-Jetpack פיתוח נייטיב   חלק מ-Android Jetpack.

רכיבים שמודעים למחזור החיים מבצעים פעולות בתגובה לשינוי בסטטוס מחזור החיים של פעילות המארח. הארטיפקט androidx.lifecycle.compose מספק ממשקי API ייעודיים שמנקים אוטומטית משאבים כשהם יוצאים מהמסך או כשהאפליקציה עוברת לרקע.

בין ממשקי ה-API העיקריים:

השילובים האלה מספקים נקודות נוחות לניהול מחזורי חיים בהיררכיה של Compose. במסמך הזה מוסבר איך אפשר להשתמש בהם באפליקציה.

איסוף נתונים על מצב מחזור החיים באמצעות תהליכים

‫Lifecycle חושף מאפיין currentStateFlow שמספק את Lifecycle.State הנוכחי כ-StateFlow של Kotlin. אפשר לאסוף את Flow בתור State. ההרשאה הזו מאפשרת לאפליקציה לקרוא שינויים במחזור החיים במהלך ההגדרה.

val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow

val currentLifecycleState by stateFlow.collectAsState()

אפשר לגשת לדוגמה הקודמת באמצעות המודול lifecycle-common. ה-method‏ currentStateAsState() זמין במודול lifecycle-runtime-compose, ומאפשר לקרוא בקלות את מצב מחזור החיים הנוכחי בשורה אחת. בדוגמה הבאה אפשר לראות איך זה עובד:

val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()

הרצת קוד באירועים במחזור החיים

במקום ליצור מחלקה נפרדת שמטמיעה את DefaultLifecycleObserver ולהוסיף אותה באופן ידני למחזור החיים, אפשר להצהיר על לוגיקה של מחזור החיים בשורה באמצעות אפקטים ספציפיים. ‫LifecycleEffects מאפשרת להריץ בלוק כשמתרחש Lifecycle.Event מסוים ישירות בתוך ההרכבה.

LifecycleEventEffect

אפשר להשתמש ב-LifecycleEventEffect כדי להריץ בלוק קוד כשמתרחש אירוע ספציפי. האפשרות הזו מתאימה במיוחד לאירועים חד-פעמיים כמו רישום ביומן או ניתוח נתונים, שבהם לא נדרשת הצלחה או תוצאה מיידית.

@Composable
fun AnalyticsTracker(screenName: String) {
    // Log an event when the app receives ON_RESUME (e.g. comes to foreground)
    LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
        Analytics.logView(screenName)
    }
}

LifecycleStartEffect

כדי להפעיל פעולות התחלה/עצירה שצריכות לפעול בזמן שהאפליקציה מופעלת (גלויות) ולנקות אותן כשהאפליקציה נעצרת (ברקע), משתמשים ב-LifecycleStartEffect.

בדומה לאפקטים אחרים של Compose (כמו LaunchedEffect), הפונקציה LifecycleStartEffect מקבלת מקשים. כשהמפתח משתנה, הבלוק מופעל שוב.

כשמתרחש אירוע Lifecycle.Event.ON_STOP או שהאפקט יוצא מהקומפוזיציה, הוא מריץ את הבלוק onStopOrDispose כדי לנקות את כל העבודה שהייתה חלק מבלוק ההתחלה.

@Composable
fun LocationMonitor(locationManager: LocationManager) {
    // Starts monitoring when ON_START is dispatched
    // Stops monitoring when ON_STOP is dispatched
    //   (or the composable leaves the screen)
    LifecycleStartEffect(locationManager) {
        val listener = LocationListener { location ->
            /* update UI */
        }
        locationManager.requestLocationUpdates(listener)
        // The cleanup block automatically runs on ON_STOP or on disposal
        onStopOrDispose {
            locationManager.removeUpdates(listener)
        }
    }
}

מידע על סוגים אחרים של תופעות לוואי זמין במאמר תופעות לוואי ב-Compose.

LifecycleResumeEffect

הפונקציה LifecycleResumeEffect פועלת באופן דומה לפונקציה LifecycleStartEffect, אבל היא קשורה לאירוע Lifecycle.Event.ON_RESUME. הוא גם מספק בלוק onPauseOrDispose שמבצע את הניקוי כש-ON_PAUSE נשלח או שהקומפוזיציה יוצאת מהמסך.

ה-API הזה שימושי למשאבים שצריכים להיות פעילים רק כשהמשתמש מקיים אינטראקציה עם האפליקציה – למשל, מצלמות או אנימציות.

@Composable
fun CameraPreview(cameraController: CameraController) {
    LifecycleResumeEffect(cameraController) {
        cameraController.startPreview()

        onPauseOrDispose {
            cameraController.stopPreview()
        }
    }
}

גישה ל-LifecycleOwner

ב-Compose, ‏ LifecycleOwner זמין באופן מרומז דרך CompositionLocal שנקרא LocalLifecycleOwner. כברירת מחדל, המארח הבסיסי בהיררכיית היצירה המוזיקלית מספק את הבעלים הזה.

val lifecycleOwner = LocalLifecycleOwner.current

ברוב האפליקציות, מספיק לבדוק את הבעלים שמוגדר כברירת מחדל או להעביר אותו לאפקטים שמודעים למחזור החיים. עם זאת, אם רוצים ליצור ניווט בהתאמה אישית או פריסות מורכבות, כדאי ליצור LifecycleOwner משלכם כדי להגדיר את מצבי מחזור החיים לקטעים ספציפיים בממשק המשתמש. לדוגמה, ספריות ניווט (כמו Navigation 3) עושות את זה באופן אוטומטי כדי לתת לכל מסך מחזור חיים משלו.

יצירת LifecycleOwner בהתאמה אישית

rememberLifecycleOwner() API מאפשר ליצור ולזכור LifecycleOwner בהתאמה אישית. זה שימושי במיוחד לרכיבים כמו HorizontalPager, שבהם רוצים שרק הדף הגלוי והמוכן יהיה RESUMED, ולקבוע maxState של STARTED לדפים הסמוכים שלא מוצגים במסך.

val pagerState = rememberPagerState(pageCount = { 10 })

HorizontalPager(state = pagerState) { pageNum ->
    val pageLifecycleOwner = rememberLifecycleOwner(
        maxState = if (pagerState.settledPage == pageNum) {
            Lifecycle.State.RESUMED
        } else {
            Lifecycle.State.STARTED
        }
    )

    CompositionLocalProvider(LocalLifecycleOwner provides pageLifecycleOwner) {
        // Your pages here. Their lifecycle-aware components respect the
        // custom maxState defined above.
    }
}

מידע נוסף על CompositionLocal זמין במאמר Locally scoped data with CompositionLocal.

שיטות מומלצות לרכיבים שמודעים למחזור החיים

  • חשוב לשמור על בקרי ממשק המשתמש כמה שיותר מצומצמים. הם לא צריכים לנסות להשיג נתונים משלהם, אלא להשתמש ב-ViewModel כדי לעשות זאת, ולעקוב אחרי אובייקט StateFlow כדי לשקף את השינויים בחזרה לממשק המשתמש.
  • נסו לכתוב ממשקי משתמש מבוססי-נתונים שבהם האחריות של בקר ממשק המשתמש היא לעדכן את ממשק המשתמש כשהנתונים משתנים, או להודיע על פעולות משתמש בחזרה אל ViewModel.
  • כדאי להוסיף את הלוגיקה של הנתונים למחלקה ViewModel. ‫ViewModel צריך לשמש כרכיב שמקשר בין בקר ממשק המשתמש לבין שאר האפליקציה. עם זאת, חשוב לזכור שViewModel לא אחראי לאחזור נתונים (למשל, מרשת). במקום זאת, ViewModel צריך לקרוא לרכיב המתאים כדי לאחזר את הנתונים, ואז להחזיר את התוצאה לבקר של ממשק המשתמש.
  • אפשר להשתמש ב-Kotlin coroutines כדי לנהל משימות ארוכות ופעולות אחרות שיכולות לפעול באופן אסינכרוני.
  • כדאי לשמור את הלוגיקה של התחלה/הפסקה בתוך הרכיב שאכן זקוק לה. כך, הלוגיקה מוסרת אוטומטית אם רכיב ממשק המשתמש הספציפי הזה מוסר מהמסך (לדוגמה, בתוך גרף ניווט או כשנראות מותנית).
  • שימוש ב-collectAsStateWithLifecycle לנתונים. אל תתחילו או תפסיקו ידנית את איסוף הנתונים על סמך אירועים במחזור החיים.Flow במקום זאת, משתמשים ב-collectAsStateWithLifecycle כדי להמיר זרמים למצב ממשק משתמש ביעילות. כך נחסכים משאבים וסוללה כי Flow מושהים כשהאפליקציה פועלת ברקע.

מידע נוסף על Flow זמין במאמר סוגים נתמכים אחרים של מצב.

תרחישי שימוש ברכיבים שמודעים למחזור החיים

רכיבים שמודעים למחזור החיים יכולים להקל מאוד על ניהול מחזורי החיים במגוון תרחישים. הנה כמה דוגמאות:

  • מעבר בין עדכוני מיקום גסים לבין עדכוני מיקום פרטניים. אפשר להשתמש ב-LifecycleStartEffect כדי להפעיל עדכוני מיקום ברמת דיוק גבוהה בזמן שהאפליקציה גלויה (ON_START), ולנקות באופן אוטומטי את מאזין המיקום או לעבור לעדכונים ברמת דיוק נמוכה כשהאפליקציה פועלת ברקע (ON_STOP).
  • הפסקה והתחלה של מאגר זמני של סרטון. משתמשים ב-LifecycleResumeEffect כדי לדחות את ההפעלה בפועל של הווידאו עד שהאפליקציה תהיה בחזית באופן מלא ואינטראקטיבית (ON_RESUME), וכדי לוודא שההפעלה מושהית והמשאבים משוחררים כשהאפליקציה פועלת ברקע (ON_PAUSE).
  • התחלה והפסקה של שידור ברשת. שימוש ב-collectAsStateWithLifecycle כדי לצפות בזרמים רציפים של נתונים (כמו Kotlin Flow משקע רשת). כך מתקבל עדכון בזמן אמת כשהאפליקציה בחזית, והאיסוף מתבטל אוטומטית כשהאפליקציה עוברת לרקע.
  • השהיה והמשך של משימות כבדות. אפשר להשתמש ב-LifecycleResumeEffect כדי להשהות עדכונים חזותיים כבדים כשהאפליקציה פועלת ברקע, ולחדש אותם כשהאפליקציה פועלת בחזית.

טיפול בטוח באירועי ON_STOP

התכונה 'יצירת תוכן' נועדה לטפל באירועים בצורה בטוחה.ON_STOP

  • המצב בטוח: אתם יכולים לעדכן את MutableState (לדוגמה, עם uiState.value = ...) בכל שלב, גם כשהאפליקציה פועלת ברקע. הכלי ליצירת הודעות ימתין עד שהאפליקציה תהיה גלויה כדי להציג את השינויים.
  • ניקוי אוטומטי: באפקטים כמו LifecycleStartEffect, בלוק הניקוי (onStopOrDispose) פועל בדיוק כשמחזור החיים עובר ל-STOPPED. כך לא תצטרכו להחזיק משאבים כבדים (כמו מצלמה או מיקום) בזמן שהאפליקציה פועלת ברקע.

מידע נוסף על MutableState זמין במאמר מצב ו-Jetpack פיתוח נייטיב.

מקורות מידע נוספים

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

צפייה בתוכן