Android Kotlin Fundamentals 09.2: WorkManager

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

מבוא

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

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

דברים שחשוב לדעת

  • כיצד להשתמש ברכיבי הארכיטקטורה של Android מסוג ViewModel , LiveData ו-Room.
  • איך מבצעים טרנספורמציות בכיתה LiveData?
  • איך בונים ומפעילים שגרה.
  • איך להשתמש במתאמים מחייבים בקישור נתונים.
  • איך לטעון נתונים שנשמרו במטמון באמצעות דפוס של מאגר.

מה תלמדו

  • איך יוצרים Worker, שמייצג יחידת עבודה?
  • איך ליצור WorkRequest כדי לבקש עבודה.
  • איך להוסיף מגבלות ל-WorkRequest כדי להגדיר איך ומתי העובד יפעל.
  • איך משתמשים ב-WorkManager כדי לקבוע משימות ברקע.

הפעולות שתבצעו:

  • יש ליצור עובד כדי לבצע משימת רקע כדי לאחזר מראש את הפלייליסט של סרטוני DevBytes מהרשת.
  • מתזמנים את העבודה של העובד מדי פעם.
  • עליך להוסיף מגבלות על WorkRequest.
  • תזמון של WorkRequest תקופתי מדי פעם.

בשיעור Lab זה אתם עובדים על אפליקציית DevBytes שפיתחתם במעבדת קוד קודמת. (אם האפליקציה לא מותקנת במכשיר שלך, אפשר להוריד את קוד ההתחלה לשיעור הזה).

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

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

במשימה הזו צריך להוריד ולבדוק את הקוד למתחילים.

שלב 1: הורדה והפעלה של האפליקציה למתחילים

תוכלו להמשיך לעבוד דרך אפליקציית DevBytes שיצרתם ב-codelab הקודם (אם היא מותקנת). לחלופין, אפשר להוריד את האפליקציה למתחילים.

במשימה זו אתם מורידים ומפעילים את האפליקציה למתחילים ובודקים את הקוד למתחילים.

  1. אם עוד לא התקנת את אפליקציית DevBytes, יש להוריד את קוד פיתוח ה-DevBytes למעבדת הקוד הזו מפרויקט DevBytesRepository מ-GitHub.
  2. מבטלים את דחיסת הקוד ופותחים את הפרויקט ב-Android Studio.
  3. מחברים את מכשיר הבדיקה או את האמולטור לאינטרנט אם הוא עדיין לא מחובר. לבנות ולהפעיל את האפליקציה. האפליקציה מאחזרת את רשימת הסרטונים של DevByte מהרשת ומציגה אותם.
  4. באפליקציה, מקישים על סרטון כלשהו כדי לפתוח אותו באפליקציית YouTube.

שלב 2: מגלים את הקוד

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

  1. ב-Android Studio, מרחיבים את כל החבילות.
  2. לעיון בחבילה של database. החבילה מכילה את הישויות של מסד הנתונים ומסד הנתונים המקומי, שמוטמע באמצעות Room.
  3. לעיון בחבילה של repository. החבילה מכילה את המחלקה VideosRepository שמסירה את שכבת הנתונים משאר האפליקציה.
  4. בודקים את שאר קוד ההתחלה בעצמכם, בעזרת העזרה של קוד הקוד הקודם.

WorkManager הוא אחד מרכיבי הארכיטקטורה של Android והוא חלק מJet Jetpack. WorkManager מיועד לעבודה ברקע שניתנת להגנה ונדרשת הפעלה מובטחת:

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

אפליקציית WorkManager פועלת ברקע, אבל היא מטפלת בבעיות תאימות ובשיטות מומלצות לתקינות הסוללה ותקינות המערכת. WorkManager מציע תאימות לרמת API 14. WorkManager בוחר דרך מתאימה לתזמון משימה ברקע, בהתאם לרמת ה-API במכשיר. היא עשויה להשתמש ב-JobScheduler (ב-API מגרסה 23 ואילך) או בשילוב של AlarmManager עם BroadcastReceiver.

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

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

  1. פותחים את הקובץ build.gradle (Module:app) ומוסיפים את התלות של WorkManager בפרויקט.

    אם משתמשים בגרסה האחרונה של הספרייה, אפליקציית הפתרון צריכה להיאסף כצפוי. אם הבעיה לא נפתרה, נסו לפתור את הבעיה או לחזור לגרסת הספרייה שמופיעה למטה.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
  1. צריך לסנכרן את הפרויקט ולוודא שאין שגיאות הידור.

לפני שמוסיפים קוד לפרויקט, חשוב להכיר את הכיתות הבאות בספרייה WorkManager:

  • Worker
    הכיתה הזו היא המקום שבו מגדירים את העבודה בפועל (המשימה) ברקע. הרחבת הכיתה תבטל את השיטה doWork(). השיטה doWork() היא המקום שבו מוסיפים את הקוד לביצוע ברקע, כמו סנכרון נתונים עם השרת או עיבוד תמונות. הטמעת את Worker במשימה הזו.
  • WorkRequest
    הכיתה הזו מייצגת בקשה להפעלת העובד ברקע. בעזרת WorkRequest אפשר להגדיר איך ומתי להריץ את משימת העובד, בעזרת Constraints, כמו המכשיר מחובר או Wi-Fi מחובר. הטמעת את WorkRequest במשימה מאוחרת יותר.
  • WorkManager
    הכיתה הזו קובעת לוח זמנים ומריצה את WorkRequest. WorkManager מתזמנים בקשות עבודה באופן שמחלק את העומס על משאבי המערכת, תוך שמירה על האילוצים שציינתם. הטמעת את WorkManager במשימה מאוחרת יותר.

שלב 1: יצירת עובד

במשימה הזו מוסיפים Worker כדי לאחזר מראש את הפלייליסט של סרטוני DevBytes.

  1. בתוך החבילה devbyteviewer, יש ליצור חבילה חדשה בשם work.
  2. בתוך החבילה work, יש ליצור כיתה חדשה של Kotlin שנקראת RefreshDataWorker.
  3. הרחבת הכיתה של RefreshDataWorker מהכיתה CoroutineWorker. צריך להעביר את context ואת WorkerParameters כפרמטרים של הרכבה.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}
  1. כדי לפתור את השגיאה של הכיתה המופשטת, יש לבטל את השיטה doWork() בתוך הכיתה RefreshDataWorker.
override suspend fun doWork(): Result {
  return Result.success()
}

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

שלב 2: הטמעת DoWork()

השיטה doWork() בתוך הכיתה Worker מופעלת בשרשור ברקע. השיטה פועלת באופן סינכרוני והיא אמורה להחזיר אובייקט ListenableWorker.Result. מערכת Android מספקת ל-Worker 10 דקות לכל היותר עד לסיום הביצוע ומחזירה אובייקט ListenableWorker.Result. בתום פרק הזמן הזה, המערכת מפסיקה את ההפעלה של Worker.

כדי ליצור אובייקט ListenableWorker.Result, יש לקרוא לאחת מהשיטות הסטטיסטיות הבאות כדי לציין את סטטוס ההשלמה של פעילות הרקע:

במשימה הזו, תטמיעו את השיטה doWork() כדי לאחזר את הפלייליסט של סרטוני DevBytes מהרשת. ניתן להשתמש שוב בשיטות הקיימות בכיתה VideosRepository כדי לאחזר את הנתונים מהרשת.

  1. בכיתה RefreshDataWorker, בתוך doWork(), יוצרים אובייקט VideosDatabase ואובייקט VideosRepository והופכים אותו לאובייקט.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)

   return Result.success()
}
  1. בכיתה RefreshDataWorker, בתוך doWork(), מעל להצהרה return, יש להתקשר לשיטה refreshVideos() בתוך בלוק try. צריך להוסיף יומן כדי לעקוב אחרי הזמן שבו העובד פועל.
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
}

כדי לפתור את השגיאה &"הפניה שלא נפתרה;" יש לייבא את retrofit2.HttpException.

  1. הנה הכיתה המלאה של RefreshDataWorker לעיונך:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {

   override suspend fun doWork(): Result {
       val database = getDatabase(applicationContext)
       val repository = VideosRepository(database)
       try {
           repository.refreshVideos()
       } catch (e: HttpException) {
           return Result.retry()
       }
       return Result.success()
   }
}

Worker מגדיר יחידת עבודה והמאפיין WorkRequest מגדיר איך ומתי כדאי להריץ את העבודה. יש שתי הטמעות בטון של הכיתה WorkRequest:

  • הכיתה OneTimeWorkRequest מיועדת למשימות חד-פעמיות. (משימה חד-פעמית מתרחשת רק פעם אחת.)
  • הכיתה PeriodicWorkRequest כוללת עבודות תקופתיות, שחוזרות על עצמן במרווחי זמן.

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

במשימה הזו, צריך להגדיר WorkRequest כדי להריץ את העובד שיצרת במשימה הקודמת ולתזמן אותו.

שלב 1: הגדרת עבודה חוזרת

בתוך אפליקציית Android, המחלקה Application היא המחלקה הבסיסית שמכילה את כל הרכיבים האחרים, כגון פעילויות ושירותים. כשיוצרים תהליך עבור האפליקציה או החבילה, נוצרת מחלקת Application (או כל סיווג משנה אחר של Application) לפני כל מחלקה אחרת.

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

  1. בכיתה DevByteApplication, יוצרים שיטה שנקראת setupRecurringWork() כדי להגדיר את העבודה החוזרת ברקע.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
  1. בשיטה setupRecurringWork(), יוצרים ומתחילים בקשת עבודה תקופתית פעם ביום, באמצעות השיטה PeriodicWorkRequestBuilder(). יש לעבור את הכיתה RefreshDataWorker שיצרת במשימה הקודמת. מרווח זמן של 1 עם יחידת זמן TimeUnit.DAYS.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build()

כדי לפתור את השגיאה, צריך לייבא את java.util.concurrent.TimeUnit.

שלב 2: תזמון WorkRequest עם WorkManager

אחרי שמגדירים את WorkRequest, אפשר לתזמן אותו עם WorkManager באמצעות השיטה enqueueUniquePeriodicWork(). שיטה זו מאפשרת להוסיף ל'הבאים בתור' PeriodicWorkRequest שמות ייחודיים, שבהם אפשר להפעיל רק PeriodicWorkRequest אחד מתוך שם מסוים בכל פעם.

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

לקבלת מידע נוסף על הדרכים לתזמן WorkRequest, יש לעיין בתיעוד של WorkManager.

  1. בכיתה RefreshDataWorker, בתחילת הכיתה, מוסיפים אובייקט נלווה. יש להגדיר שם עבודה כדי לזהות את העובד הזה באופן ייחודי.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
  1. בקורס 'DevByteApplication' בסוף שיטת setupRecurringWork(), מתזמנים את העבודה באמצעות השיטה enqueueUniquePeriodicWork(). יש לעבור ברמת KEEP עבור ה- נקודות נקודות קיימות. יש להעביר את הפרמטר repeatingRequest כפרמטר PeriodicWorkRequest.
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)

אם קיימת עבודה בהמתנה (שלא הושלמה) עם אותו שם, הפרמטר ExistingPeriodicWorkPolicy.KEEP גורם ל-WorkManager לשמור את היצירה המחזורית הקודמת ולמחוק את בקשת העבודה החדשה.

  1. בתחילת הכיתה DevByteApplication, יוצרים אובייקט CoroutineScope. צריך להעביר את הפרמטר Dispatchers.Default כפרמטר של ה-constructor.
private val applicationScope = CoroutineScope(Dispatchers.Default)
  1. בשיעור DevByteApplication, מוסיפים שיטה חדשה בשם delayedInit() כדי להתחיל שגרה.
private fun delayedInit() {
   applicationScope.launch {
   }
}
  1. בתוך השיטה delayedInit(), יש להתקשר אל setupRecurringWork().
  2. צריך להעביר את אתחול העץ מהשיטה onCreate() לשיטת delayedInit().
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}
  1. בכיתה DevByteApplication, בסוף השיטה onCreate(), צריך להוסיף קריאה לשיטה delayedInit().
override fun onCreate() {
   super.onCreate()
   delayedInit()
}
  1. פותחים את החלונית Logcat בתחתית החלון של Android Studio. סינון לפי RefreshDataWorker.
  2. כדאי להפעיל את האפליקציה. האפליקציה WorkManager מתזמנת את העבודה החוזרת שלך באופן מיידי.

    בחלונית Logcat , שימו לב להצהרות היומן שמוכיחות שבקשת העבודה מתוזמנת, ולאחר מכן פועלת בהצלחה.
D/RefreshDataWorker: Work request for sync is run
I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]

היומן WM-WorkerWrapper מוצג מספריית WorkManager, כך שאי אפשר לשנות את הודעת היומן הזו.

שלב 3: (אופציונלי) קובעים מרווח זמן מינימלי ל-WorkRequest

בשלב זה מפחיתים את מרווח הזמן מיום אחד ל-15 דקות. פעולה זו מאפשרת להציג את היומנים של בקשת עבודה תקופתית בפעולה.

  1. בכיתה DevByteApplication, בתוך השיטה setupRecurringWork(), יש להגיב על ההגדרה הנוכחית repeatingRequest. הוספה של בקשת עבודה חדשה עם מרווח תקופתי של 15 דקות.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()
  1. פותחים את החלונית Logcat ב-Android Studio ומסננים לפי RefreshDataWorker. כדי לנקות את היומנים הקודמים, לוחצים על ניקוי יומן רישום .
  2. יש לך אפשרות להריץ את האפליקציה, ומערכת WorkManager מתזמנת את העבודה החוזרת שלך באופן מיידי. בחלונית Logcat , שימו לב ליומנים – בקשת העבודה פועלת פעם ב-15 דקות. ממתינים 15 דקות כדי לראות קבוצה נוספת של יומני בקשות עבודה. ניתן להשאיר את האפליקציה פעילה או לסגור אותה. מנהל העבודה אמור להמשיך לפעול.

    לתשומת ליבך, לפעמים המרווח קצר מ-15 דקות, ולפעמים יותר מ-15 דקות. (התזמון המדויק כפוף לאופטימיזציות של הסוללה של מערכת ההפעלה).
12:44:40 D/RefreshDataWorker: Work request for sync is run
12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
12:59:24 D/RefreshDataWorker: Work request for sync is run
12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:15:03 D/RefreshDataWorker: Work request for sync is run
13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:29:22 D/RefreshDataWorker: Work request for sync is run
13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:44:26 D/RefreshDataWorker: Work request for sync is run
13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
 

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

במשימה הבאה תטפלו בבעיה על ידי הוספת אילוצים.

במשימה הקודמת, השתמשת ב-WorkManager כדי לתזמן בקשת עבודה. במשימה הזו מוסיפים קריטריונים לזמן ביצוע העבודה.

כשמגדירים את WorkRequest, אפשר לציין אילוצי זמן להפעלת Worker. לדוגמה, אפשר לציין שהעבודה תבוצע רק כשהמכשיר לא פעיל או רק כשהמכשיר מחובר ל-Wi-Fi ומחובר אליו. אפשר גם לציין מדיניות לגבי ניסיון חוזר. האילוצים הנתמכים הם השיטות המוגדרות ב-Constraints.Builder. למידע נוסף: הגדרת הבקשות לעבודה.

שלב 1: מוסיפים אובייקט אילוץ ומגדירים אילוץ אחד

בשלב זה, יוצרים אובייקט Constraints ומגדירים אילוץ אחד לאובייקט, מגבלה על סוג הרשת. (קל יותר לזהות את היומנים באמצעות מגבלה אחת בלבד. בשלב מאוחר יותר מוסיפים עוד אילוצים).

  1. בכיתה DevByteApplication, בתחילת setupRecurringWork(), צריך להגדיר val מסוג Constraints. יש להשתמש בשיטה Constraints.Builder().
val constraints = Constraints.Builder()

כדי לפתור את השגיאה, צריך לייבא את androidx.work.Constraints.

  1. יש להשתמש בשיטה setRequiredNetworkType() כדי להוסיף אילוץ של סוג רשת לאובייקט constraints. צריך להשתמש ב-UNMETERED enum כדי שבקשת העבודה תפעל רק כשהמכשיר מחובר לרשת שלא נמדדת.
.setRequiredNetworkType(NetworkType.UNMETERED)
  1. יש להשתמש בשיטה build() כדי ליצור אילוצים מהבונה.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()

עכשיו עליך להגדיר את האובייקט Constraints החדש לבקשת העבודה.

  1. בכיתה DevByteApplication, במסגרת השיטה setupRecurringWork(), מגדירים את האובייקט Constraints לבקשת העבודה המחזורית, repeatingRequest. כדי להגדיר אילוצים, יש להוסיף את השיטה setConstraints() מעל הקריאה לשיטה build().
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()

שלב 2: מריצים את האפליקציה ושמים לב ליומנים

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

  1. כדי לבטל משימות שתוזמנו בעבר, יש להסיר את האפליקציה מהמכשיר או מהאמולטור.
  2. פותחים את החלונית Logcat ב-Android Studio. בחלונית Logcat , לוחצים על הסמל Clear logcat כדי לנקות את היומנים הקודמים. סינון לפי work.
  3. יש להשבית את ה-Wi-Fi במכשיר או באמולטור כדי לראות כיצד אילוצים פועלים. הקוד הנוכחי מגדיר אילוץ אחד בלבד, ופירושו שהבקשה צריכה לפעול רק ברשת שאינה נמדדת. מכיוון שאין חיבור ל-Wi-Fi, המכשיר לא מחובר לרשת, נמדד או לא נמדד. לכן האילוץ הזה לא יעמוד.
  4. מריצים את האפליקציה ושמים לב לחלונית Logcat . ה-WorkManager לתזמן את משימת הרקע באופן מיידי. המשימה לא מופעלת בגלל אילוץ הרשת.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
  1. מפעילים את ה-Wi-Fi במכשיר או באמולטור וצופים בחלונית Logcat . עכשיו משימת הרקע המתוזמנת פועלת בערך 15 דקות, כל עוד היא עומדת במגבלת הרשת.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
11:31:47 D/RefreshDataWorker: Work request for sync is run
11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
11:46:45 D/RefreshDataWorker: Work request for sync is run
11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:03:05 D/RefreshDataWorker: Work request for sync is run
12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:16:45 D/RefreshDataWorker: Work request for sync is run
12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:31:45 D/RefreshDataWorker: Work request for sync is run
12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:47:05 D/RefreshDataWorker: Work request for sync is run
12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
13:01:45 D/RefreshDataWorker: Work request for sync is run
13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]

שלב 3: מוסיפים אילוצים נוספים

בשלב זה מוסיפים את המגבלות הבאות ל-PeriodicWorkRequest:

  • הסוללה לא חלשה.
  • המכשיר בטעינה.
  • מכשיר לא פעיל; זמין רק ברמת API 23 (Android M) ואילך.

מיישמים את האפשרויות הבאות בכיתה DevByteApplication.

  1. במחלקה DevByteApplication, בתוך השיטה setupRecurringWork(), יש לציין שבקשת העבודה צריכה לפעול רק אם רמת הטעינה של הסוללה נמוכה. עליך להוסיף את האילוץ לפני הקריאה לשיטת build(), ולהשתמש בשיטה setRequiresBatteryNotLow().
.setRequiresBatteryNotLow(true)
  1. יש לעדכן את בקשת העבודה כך שהיא תרוץ רק כשהמכשיר בטעינה. עליך להוסיף את האילוץ לפני הקריאה לשיטת build(), ולהשתמש בשיטה setRequiresCharging().
.setRequiresCharging(true)
  1. יש לעדכן את בקשת העבודה כך שהיא תרוץ רק כשהמכשיר לא פעיל. עליך להוסיף את האילוץ לפני הקריאה לשיטת build(), ולהשתמש בשיטה setRequiresDeviceIdle(). המגבלה הזו מפעילה את בקשת העבודה רק כשהמשתמש לא משתמש במכשיר באופן פעיל. התכונה הזו זמינה רק ב-Android מגרסה 6.0 (Marshmallow) ואילך, לכן צריך להוסיף תנאי לגרסה SDK מגרסה M ואילך.
.apply {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       setRequiresDeviceIdle(true)
   }
}

זוהי ההגדרה המלאה של האובייקט constraints.

val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresBatteryNotLow(true)
       .setRequiresCharging(true)
       .apply {
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               setRequiresDeviceIdle(true)
           }
       }
       .build()
  1. בתוך השיטה setupRecurringWork(), משנים את מרווח הבקשות חזרה פעם ביום.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()

כאן מיושמת השיטה המלאה של setupRecurringWork(), עם יומן כדי שתוכלו לעקוב אחר התזמון של בקשת העבודה המחזורית.

private fun setupRecurringWork() {

       val constraints = Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .setRequiresBatteryNotLow(true)
               .setRequiresCharging(true)
               .apply {
                   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                       setRequiresDeviceIdle(true)
                   }
               }
               .build()
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
               .setConstraints(constraints)
               .build()
       
       Timber.d("Periodic Work request for sync is scheduled")
       WorkManager.getInstance().enqueueUniquePeriodicWork(
               RefreshDataWorker.WORK_NAME,
               ExistingPeriodicWorkPolicy.KEEP,
               repeatingRequest)
   }
  1. כדי להסיר את בקשת העבודה המתוזמנת בעבר, צריך להסיר את האפליקציה DevBytes מהמכשיר או מהאמולטור.
  2. מריצים את האפליקציה, ו-WorkManager מתזמנים מיד את בקשת העבודה. בקשת העבודה פועלת פעם ביום, כאשר כל האילוצים מתקיימים.
  3. בקשת העבודה הזו תרוץ ברקע כל עוד האפליקציה מותקנת, גם אם האפליקציה לא פועלת. מסיבה זו, עליך להסיר את האפליקציה מהטלפון.

כל הכבוד! יישמת וקבעת בקשת עבודה ידידותית לסוללה לצורך שליפה יומית של סרטונים באפליקציית DevBytes. WorkManager יתזמן ויריץ את העבודה, תוך אופטימיזציה של משאבי המערכת. המשתמשים שלך והסוללות שלהם יהיו שמחים מאוד.

פרויקט ב-Android Studio: DevBytesWorkManager.

  • ממשק ה-API של WorkManager מאפשר לתזמן משימות אסינכרוניות הניתנות להפעלה באופן אמין.
  • רוב האפליקציות בעולם האמיתי צריכות לבצע משימות ארוכות של רקע. כדי לתזמן משימה ברקע באופן אופטימלי ויעיל, יש להשתמש ב-WorkManager.
  • הכיתות העיקריות בספרייה של WorkManager הן Worker, WorkRequest ו-WorkManager.
  • הכיתה Worker מייצגת יחידת עבודה. כדי להטמיע את משימת הרקע, יש להרחיב את הכיתה Worker ולעקוף את השיטה doWork().
  • הכיתה WorkRequest מייצגת בקשה לביצוע יחידת עבודה. WorkRequest היא סיווג הבסיס לציון פרמטרים של עבודה שתזמנת ב-WorkManager.
  • יש שתי הטמעות ממשיות של הכיתה WorkRequest: OneTimeWorkRequest למשימות חד-פעמיות ו-PeriodicWorkRequest לבקשות עבודה תקופתיות.
  • כשמגדירים את WorkRequest, אפשר לציין Constraints שיציין מתי ה-Worker צריך לפעול. המגבלות כוללות, למשל, אם המכשיר מחובר לחשמל, אם המכשיר לא פעיל או אם Wi-Fi מחובר.
  • כדי להוסיף אילוצים ל-WorkRequest, יש להשתמש בשיטות שהוגדרו המפורטות בתיעוד של Constraints.Builder. לדוגמה, כדי לציין שה-WorkRequest לא צריך לפעול אם סוללת המכשיר חלשה, יש להשתמש בשיטה setRequiresBatteryNotLow() שהוגדרה.
  • אחרי שמגדירים את WorkRequest, צריך להקצות את המשימה למערכת Android. כדי לעשות זאת, צריך לתזמן את המשימה באמצעות אחת מWorkManagerenqueue השיטות הבאות.
  • הזמן המדויק שבו ה-Worker מופעל תלוי באילוצים שבהם נעשה שימוש ב-WorkRequest ובאופטימיזציות של המערכת. האפליקציה WorkManager נועדה לתת את ההתנהגות הטובה ביותר האפשרית, בכפוף להגבלות האלה.

קורס אוניברסיטה:

התיעוד של מפתח Android:

אחר:

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

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

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

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

שאלה 1

איך הטמעת את הבטון של הכיתה WorkRequest?

OneTimeWorkPeriodicRequest

OneTimeWorkRequest ו-PeriodicWorkRequest

OneTimeWorkRequest ו-RecurringWorkRequest

OneTimeOffWorkRequest ו-RecurringWorkRequest

שאלה 2

באילו מהכיתות הבאות WorkManager משתמש כדי לתזמן את משימת הרקע ב-API 23 ואילך?

הוספה של JobScheduler בלבד

BroadcastReceiver ו-AlarmManager

AlarmManager ו-JobScheduler

Scheduler ו-BroadcastReceiver

שאלה 3

באיזה API את משתמשת כדי להוסיף אילוצים ל-WorkRequest?

setConstraints()

addConstraints()

setConstraint()

addConstraintsToWorkRequest()

בשיעור הבא: 10.1 סגנונות ועיצובים

קישורים למעבדות אחרות של הקוד בקורס הזה זמינים בדף הנחיתה של Android Kotlin Fundamentals Codelabs.