מבוא לתהליכים

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

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

הנתונים מאוחזרים מהתהליך על ידי הצרכן בתהליך שנקרא איסוף. לזרימות ב-Kotlin יש פונקציה collect() שאפשר להשתמש בה למטרה הזו. מה שקורה בתהליך האיסוף תלוי בסוג התהליך.

תהליכים ב-Kotlin‏ (Flow<T>) הם קרים כברירת מחדל, כלומר הקוד של ה-flow builder יוצר נתונים רק כשמפעילים את collect(). לעומת זאת, תהליך חם יוצר נתונים באופן מיידי, ומאחסן אותם בזיכרון כתור עד שהם נצרכים. מכיוון שהנתונים נשמרים בזיכרון, תהליך 'זרימה חמה' נחשב כמצב סטטי.

אפשר להמיר תהליכים מ-cold ל-hot באמצעות האופרטור shareIn (מידע נוסף זמין במאמר הפיכת תהליכים מ-cold ל-hot באמצעות shareIn). אפשר גם להשתמש ב-SharedFlow או ב-StateFlow כדי להפוך תהליך מ-cold ל-hot.

איך האפליקציה לדוגמה משתמשת בתהליכים

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

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

  fun getStructuresState(): StateFlow<List<StructureModel>?> =
    homeClient
      .structures()
      .map { structures -> structures.map { StructureModel(it.name, it) }.sortedBy { it.name } }
      .handleErrors()
      .flowOn(Dispatchers.IO)
      .stateIn(scope = viewModelScope, started = SharingStarted.WhileSubscribed(), null)

emitAll() אוסף את כל הערכים מהזרימה הנתונה ומעביר אותם למצטבר. stateIn() משתף את הערך האחרון שהופץ ממכונה אחת שפועלת של תהליך הזרימה ב-upstream עם כמה מנויים ב-downstream. מידע נוסף זמין במסמך העזרה kotlinx.coroutines.flow.

Jetpack פיתוח נייטיב

כדי לאחסן אובייקטים של תהליכים בזיכרון המקומי ולמנוע את סגירתם, צריך להשתמש ב-API של Kotlin‏ remember.

ב-Jetpack Compose, אם משתמשים בזה עם collectAsStateWithLifecycle(),‏ Jetpack מנהל באופן אוטומטי את ההרשמות לזרמים ואת ביטול ההרשמות מהם, על סמך המצב שבו ממשק המשתמש של האפליקציה שמוצג בו המצב הזה נמצא בפועל בחזית.

כדי לעשות זאת, פשוט קוראים ל-API באפליקציית הדוגמה. באמצעות הפונקציה getStructuresState() שצוינה למעלה:

val structuresList by
    remember(globalViewModel) { globalViewModel.getStructuresState() }.collectAsStateWithLifecycle()

עכשיו, כשמצב כלשהו של המבנה ישתנה (למשל name), הפונקציה הניתנת לקיפול שמשתמשת בו תשקף את המצב המעודכן באופן אוטומטי. באפליקציה לדוגמה, זוהי הפונקציה HomeActivityContent().

משאבים

מידע נוסף על Kotlin, על זרמים, על פונקציות רפיטיביות ועל Jetpack Compose זמין במקורות המידע הבאים: