PracticU

Progress Dialog

בלי כתוביותעם כתוביות
PracticU › קורס פיתוח אפליקציות - לאנדרואיד - Android - ב-JAVA › Progress Dialog
מילון מושגים:
תהליכון - יחידת ביצוע בתוך תהליך, המאפשרת להריץ כמה מהלכים במקביל ולחלוק את אותו זיכרון.
Callback - פונקציה שמועברת כארגומנט לפונקציה אחרת כדי שתופעל מאוחר יותר, לרוב בסיום פעולה.
כפתור - רכיב בממשק המשתמש שהמשתמש לוחץ עליו כדי להפעיל פעולה, כמו שליחת טופס או מעבר לדף אחר.
לולאה - מבנה בקרה שחוזר על קטע קוד שוב ושוב כל עוד תנאי מתקיים או עבור כל פריט באוסף.
מחלקה - תבנית בתכנות מונחה עצמים שמגדירה אילו נתונים ופעולות יהיו לאובייקטים שנוצרים ממנה.
בנאי - מתודה מיוחדת שמופעלת אוטומטית בעת יצירת אובייקט ממחלקה, ומאתחלת את ערכיו ההתחלתיים.
אירוע - התרחשות שהמערכת מזהה ויכולה להגיב לה, כמו לחיצת עכבר, הקשה או סיום פעולה.
בוליאני - סוג נתונים שיכול לקבל אחד משני ערכים בלבד: אמת (true) או שקר (false).

Progress Dialog
ProgressDialog מציג עיגול מסתובב כדי להודיע למשתמש שתהליך ארוך, כמו הורדה או חישוב, מתבצע ברקע. השיעור מראה למה הצגה פשוטה לא עובדת, ואיך פותרים זאת עם Thread, Callback וכפתור ביטול.
השלבים העיקריים
1. ההדמיה: כפתור Download שמריץ לולאה של 100 איטרציות עם Thread.sleep של 100 מילי-שניות, בתוך try/catch, בסך הכול כ-10 שניות. בזמן הזה ה-UI תקוע והכפתור נשאר לחוץ.
2. הניסיון הפשוט: יוצרים ProgressDialog עם setTitle, setMessage, setIcon, קוראים ל-show לפני התהליך ול-dismiss אחריו. התיבה לא מוצגת, כי התהליך תוקע את ה-UI ואי אפשר לרענן אותו.
3. הפעלה ב-Thread נפרד: מוציאים את הלולאה למחלקה Downloader שמממשת Runnable, ומפעילים אותה עם new Thread(downloader).start(). קריאה ישירה ל-run תהיה קריאה רגילה, שלא רצה במקביל.
4. דיווח על סיום: start חוזרת מיד, ולכן dismiss יתבצע מוקדם מדי. מגדירים ממשק DownloaderCallbacks עם downloadComplete, שמתקבל בקונסטרקטור של Downloader, ו-MainActivity מממשת אותו ושולחת this. הפונקציה מבצעת dismiss על ה-ProgressDialog, שהועבר למשתנה גלובלי. השם callback ולא listener, כי כאן רק מודיעים שהסתיים, ואין האזנה לאירועים תוך כדי.
5. ביטול: setCancelable(false) מונע סגירה בלחיצה בחוץ, ולכן מוסיפים setButton מסוג BUTTON_NEGATIVE (Cancel) עם מאזין DialogInterface.OnClickListener. ב-onClick קוראים ל-downloader.cancelDownload().
6. דגל ביטול: ב-Downloader משתנה boolean cancelRequested, שמוגדר true ב-cancelDownload. בכל איטרציה בודקים אותו, ואם הוא true קוראים ל-downloadCanceled בממשק ויוצאים מהפונקציה בלי להגיע ל-downloadComplete.
שימו לב
- התיבה נעלמת אוטומטית בלחיצה על Cancel, ולכן אין חובה לבצע בו dismiss.
- הדגל רק מבקש ביטול, והלולאה עצמה היא שעוצרת את התהליך.
אחרי השיעור אפשר להציג למשתמש תיבת המתנה בזמן תהליך ארוך שרץ ב-Thread נפרד, ולאפשר לו לבטל אותו.
השיעור הבא בקורס: Custom Dialog

פרקי ההרצאה: Progress Dialog

  1. 00:00

    מהו Progress Dialog ומתי משתמשים בו

  2. 00:43

    הדמיית תהליך ארוך עם לולאה

  3. 02:00

    הצגת ProgressDialog עם Show ו-Dismiss

  4. 03:40

    למה הדיאלוג לא מוצג

  5. 04:36

    הרצת התהליך ב-Thread נפרד

  6. 05:29

    מחלקת Downloader שמממשת Runnable

  7. 07:22

    בעיית הסגירה המיידית של הדיאלוג

  8. 08:36

    ממשק Callbacks להודעה על סיום

תמלול ההרצאה: Progress Dialog

הטקסט המלא של הדקות הראשונות בהרצאה «Progress Dialog» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.

  1. 00:03

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

  2. 00:23

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

  3. 00:38

    אז בואו נניח שיש לנו פה לחצן והלחצן הזה מיועד לבצע דאונלואוד של משהו אז נגדיר עליו את המילה דאונלואוד onclick button download underline onclick ובואו ניגש ונייצר לנו את האירוע ובאירוע אנחנו רוצים לבנות איזשהו קטע קוד שמבצע הדמיה למשהו שלוקח הרבה זמן.

  4. 01:04

    אז בואו ניקח לולאה שרצה 100 פעם וכל פעם בלולאה יש לנו פה delay על ידי thread.slip של 100 מילי שניות. סך הכל הלולאה הזאת מתבצעת 10 שניות.

  5. 01:21

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

  6. 01:34

    בואו נריץ, בואו נלחץ על הלחצן ושימו לב שה-UI תקוע הלחצן אפילו נראה כאילו שהוא באמצע הלחיצה יוזר לא יכול לגעת בכלל בשום דבר ב-UI הזה ורק אחרי 10 שניות הנה עכשיו הלחצן השתחרר ורק עכשיו היוזר יכול לבצע פעולות כמובן שתהליך ה-Downloading יכול לקחת קצת פחות זמן או קצת יותר זמן אבל אנחנו רוצים להציג לו תוך כדי

  7. 02:01

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

  8. 02:20

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

  9. 02:44

    לדוגמה set title, downloading, לדוגמה set message, please wait, לדוגמה set icon, בתוך תיקי הדרואיבול הגדרתי איזשהו אייקון שנקרא downloading, ואחרי שהגדרנו את כל ההגדרות האלה אנחנו יכולים לבצע show.

  10. 03:12

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

  11. 03:33

    בואו נריץ. אז הנה התוכנית רצה ואנחנו הולכים ללחוץ על הלחצן אבל שימו לב שזה לא הולך לעבוד. מה זאת אומרת? דיאלוג שכביכול הצגנו לא מוצגת והשאלה היא למה?

  12. 03:52

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

  13. 04:17

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

  14. 04:37

    Thread זה פשוט מאוד איזושהי פעילות שמתרחשת במקביל לכל פעילות אחרת שקיימת באפליקציה. לדוגמה האקטיביטי זה פעילות אחת וכל ה-UI שיש באקטיביטי זאת אותה פעילות שמנהלת את האקטיביטי ואנחנו יכולים לפתוח כאילו פעילות אחרת שזה בעצם thread נפרד שרץ במקביל ואז שני הדברים יכולים לרוץ ביחד אם כל הקטע הזה שמתבצע במשך הרבה זמן

  15. 05:08

    וכביכול תוקע את התוכנית יתבצע ב-thread נפרד חיצונית לאקטיביטי ולא קשור ל-activity אז כל ה-UI של ה-activity גם יוכל לעבוד ולכן ה-Progress Dialog תוכל להיות מוצגת.

  16. 05:24

    כל מה שאנחנו צריכים לעשות זה פשוט להוציא את הלולאה הזאת החוצה ולהפעיל את זה ב-thread נפרד. אז אנחנו צריכים ללכת ולבנות מחלקה חיצונית, בואו נקרא למחלקה הזאת לדוגמה Downloader ואנחנו רוצים to implement את runable יש כל מיני שיטות להגדיר thread נפרד זאת אחת מהן אז בואו נממש את הפונקציות ויש לנו רק פונקציה אחת

  17. 05:45

    שנקראת run והפונקציה הזאת run זאת פונקציה שמסוגלת להתבצע ב-thread נפרד במקביל לכל פעילות האפליקציה זאת אומרת שאנחנו רוצים עכשיו לקחת את הקוד הזה בואו נגזור אותו נדביק אותו פה ועכשיו זה נמצא במחלקה חיצונית לגמרי.

  18. 06:18

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

  19. 06:35

    אנחנו רוצים לגשת ולבנות קודם כל אובייקט מהדאונלודר דאון לואודר נקודה, או ניקח אובייקט דאון לואודר שווה ניו דאון לואודר ואנחנו רוצים לבנות אובייקט מטיפוס Thread שווה ניו Thread ולתת לקונסטרקטור שלו את אובייקט הדאון לואודר כי הוא יורש את Runable או מממש את Runable ואז אנחנו רוצים לבוא ל-Thread ולקרוא לפונקציית Start

  20. 07:14

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

  21. 07:28

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

  22. 07:42

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

  23. 08:04

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

  24. 08:24

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

  25. 08:41

    אז בואו ניגש לתוך המחלקת הדאונלודר ונבנה מנגנון דומה למנגנון הליסנר שבנינו בעבר. ואנחנו צריכים לבנות כאן איזשהו public interface ובואו נקרא לו Downloader Callbacks.

  26. 08:58

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

  27. 09:15

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

  28. 09:36

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

  29. 09:53

    בואו נבנה את זה בקונסטרקטור. ניקח public Downloader ובקונסטרקטור נקבל Downloader Callbacks ונשים אותו בתוך This Callbacks ועכשיו אם מישהו יוצר אובייקט מה-Downloader אז הוא מחויב לתת לנו איזשהו אובייקט שמממש את האינטרפייס Downloader Callbacks אנחנו שמים אותו באזור הגלובלי וברגע שכל הפעילות של הפונקציה הזאתי הסתיימה אנחנו אנחנו פשוט יכולים לבוא ל-callbacks ולקרוא

  30. 10:32

    לפונקציה Download Complete ואז אנחנו יכולים לקבל את ה-callback בעצם שהפעילות הסתיימה ונעשה שם מה שאנחנו רוצים. עכשיו אנחנו צריכים לגשת ל-Main Activity וקודם כל כבר כאן בקונסטרקטור אנחנו רואים שאנחנו צריכים לתת איזשהו אובייקט אז בואו ניתן את ה-dis ונאמר ל-Main Activity כאן על ידי השיטה

  31. 10:59

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

  32. 11:33

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

לקורס המלא: קורס פיתוח אפליקציות לאנדרואיד

ההרצאה הקודמת: Time Dialog

ההרצאה הבאה: Custom Dialog

הרצאות קשורות מקורסים אחרים

  • הצגת Progress alert ב-Xcode
  • תיבות דו-שיח - Build-In Dialog Boxes

קורסים נוספים במסלול

  • קורס יסודות התכנות - שפת JAVA - קורס ג'אווה למתחילים
  • קורס פיתוח אפליקציות - לאייפון iPhone iOS - ב-Swift-Xcode
  • קורס פלאטר - Flutter - שפת DART של גוגל למובייל - פיתוח אפליקציות לאנדרואיד ואייפון
  • קורס PhoneGap - פיתוח אפליקציות לאנדרואיד ואייפון