
onClick ב-XMLonClick נתמך ב-XML: לאירועים אחרים, כמו לחיצה ארוכה (long click) או מקשים שנלחצו ב-EditText, אי אפשר להירשם דרך ה-XML.PrimesManager מקבלת גבול עליון ומחזירה ArrayList<Integer> של כל המספרים הראשוניים עד אליו. הבדיקה isPrime מחזירה false למספר שאינו גדול מ-1, ובודקת אם מספר כלשהו מ-2 ועד המספר מחלק אותו. כדי לדמות פעולה ארוכה מוסיפים Thread.sleep של 100 אלפיות שנייה, בתוך try/catch. הלחצן Find Primes מציג את התוצאה ב-TextView, ולחיצה על ה-activity מנקה אותו. הלחצן נתקע כמה שניות והתוצאה מופיעה רק בסוף, אבל אנחנו רוצים לקבל דיווח בכל פעם שנמצא מספר ראשוני.PrimesManager נכתבה לפני MainActivity, ולכן אינה מכירה אותה ואינה יכולה לקרוא לפונקציה שלה. כאן נכנס ה-Listener Pattern: מקבלים אובייקט שמממש ממשק מוסכם, וקוראים לפונקציה שבו בלי להכיר את המחלקה שלו.OnFoundPrimeListener, עם פונקציה אחת onFoundPrime(int prime). שם הממשק מתחיל ב-On ומסתיים ב-Listener.PrimesManager משתנה פרטי מסוג הממשק, listener.setOnFoundPrimeListener(OnFoundPrimeListener listener) שומרת את האובייקט. set שומר אובייקט אחד, ו-add מוסיף לאוסף של מאזינים, כשבכל מקרה כל המאזינים מקבלים דיווח.listener.onFoundPrime(i), אבל רק אם listener != null. כך המחלקה לא תלויה בכך שמישהו נרשם.MainActivity: קוראים ל-setOnFoundPrimeListener לפני הפעלת הפעולה, ומעבירים אובייקט שמממש את הממשק.PrimesLogger מממשת את הממשק (Alt+Enter ו-Implement methods) וכותבת ל-LogCat עם Log.i ועם תג PrimesTester. מייצרים ממנה אובייקט ושולחים אותו. הדרך הכי פחות נפוצה, מתאימה אם הקוד רב.new PrimesManager.OnFoundPrimeListener() { ... } בתוך הקריאה ל-setOnFoundPrimeListener. Java יוצרת מאחורי הקלעים מחלקה ואובייקט, והקוד כתוב במקום. נפוצה כשהקוד קצר, ויש בה גישה ל-activity עצמו.this. מציעים ב-Alt+Enter את Make MainActivity implement, והפונקציה onFoundPrime נכתבת ב-activity. מתאימה כשהקוד מתארך ורוצים להוציאו מהלחצן.PrimesManager.OnFoundPrimeListener.הטקסט המלא של הדקות הראשונות בהרצאה «The Listener Pattern» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
אנחנו מגיעים לסדרת סרטונים בהם אנחנו הולכים לדבר על אירועים ולראות כל מיני דברים בנוגע לאירועים שעדיין לא ראינו.
אז קודם כל, מה זה בעצם אירוע? אנחנו יודעים שאירוע זאת פעילות שמתרחשת בתוך מחלקה, כאשר היא מדווחת משהו לעולם החיצון.
לדוגמה, אם יש לנו לחצן, לחצן זה אובייקט ממחלקה Button, והלחצן יודע שהיוזר לחץ עליו קליק, ואז אנחנו יכולים להירשם לאירוע קליק, איך תמיד היינו עושים את זה?
היינו הולכים כאן לקובץ ה-XML, היינו רושמים onclick=do something, ובשם של פונקציה ניגשים אלט אנטר, אוד אנטר, מגיעים לקוד הג'אווה וכותבים כאן קוד.
אז יש פה שני צדדים לנושא האירוע, קודם כל הלחצן עצמו יודע שלחצו עליו, ואז ברגע שזה קרה הוא מדווח את העובדה הזאת לעולם החיצון. אנחנו העולם החיצון, ללחצן, ואנחנו צריכים להירשם לאירוע הדבר הזה נקרא רישום לאירוע ואז אנחנו בעצם תופסים את האירוע כאן בפונקציה כאשר האירוע מתרחש מתוך המחלקה button אנחנו מקבלים את
הקריאה לפונקציה ומבצעים את הקוד הדרוש זאת אומרת הלחצן קורא לפונקציה הזאת כאשר לוחצים עליו קליק זה כל הסיפור בנוגע לאירוע משהו קרה במחלקה במקרה הזה user לחץ קליק על אובייקט ואז המחלקה רוצה להודיע לנו את זה.
המחלקה לא מכירה אותנו, היא לא יודעת מי זה הקוד שלנו, אנחנו היינו צריכים לבוא ולומר למחלקה, הנה יש לנו פונקציה, הנה הפונקציה היא נקראת do something, בבקשה תקראי לפונקציה הזאת, כאשר היוזר ילחץ קליק.
אז מה בדיוק כל הבעיה בסיפור הזה? אז למעשה עד עכשיו לא ראינו שום בעיה, כאשר רצינו לכתוב איזשהו קוד שיתבצע כתגובה לאירוע קליק, אז זה מה שעשינו.
אבל הנה כמה סיבות שהדבר הזה לא יספיק מקרים מסוימים דבר ראשון רק עבור אירועי און קליק אפשר להירשם דרך הxml יש עוד המון אירועים אחרים לדוגמה long click לחיצה ארוכה על ידי הלחצן שהוא לוחץ על הלחצן או על רכיב אחר ולא עוזב את הלחצן או את הרכיב ורק אחרי הרבה זמן עוזב ואז האירוע הזה
בעצם מתרחש לדוגמה אירועי מקלדת כשהיוזר מקליד בוא נניח בתוך אדי טקסט ואנחנו רוצים תוך כדי ההקלדה לראות מהם המקשים שנלחצו ויש עוד המון אירועים אחרים.
אנחנו לא יכולים להירשם דרך קובץ ה-XML לכל האירועים האלה, כי פשוט אין אפשרות כזאת באפליקציית אנדרואיד, לפחות לא בגרסת האנדרואיד הזאת.
רק אירוע on-click ניתן להירשם אליו דרך קוד ה-XML. זאת אומרת שאנחנו צריכים כן להירשם לכל האירועים האלה בדרך אחרת, והדרך הזאת היא דרך קוד ה-Java.
קוד ה-Java מאפשר לנו להירשם לכל האירועים, לקלוט אותם כשהם מתרחשים ולכתוב קוד שיתבצע כתגובה לאירועים האלה. אז קודם כל זאת סיבה ראשונה למה רישום דרך קובץ ה-XML הוא לפעמים בלתי אפשרי בכלל.
סיבה שנייה יכולה להיות שאנחנו רוצים ליצור את הלחצן הזה בצורה דינמית, זאת אומרת דרך קוד הג'אווה אנחנו פתאום יוצרים לחצן חדש, הוא בכלל לא היה בכתיבת קובץ ה-XML.
אם אנחנו יוצרים לחצן חדש כמובן שאנחנו רוצים להירשם לאירועים שלו ואז אנחנו נוכל לעשות את זה רק בקוד הג'אווה. אז יש כל מיני סיבות שבגללם אנחנו לא יכולים לבצע את הרישום הזה בצורה כזאת.
בכדי להבין באמת איך אנחנו צריכים להירשם ומה קורה מאחורי הקלעים, אנחנו צריכים להבין את שני המקרים, גם את המקרה שמתרחש מתוך המחלקה עצמה, מתוך ה-button, וגם את הקוד שאנחנו צריכים לכתוב בשביל להירשם באזור שלנו.
אנחנו לא יכולים להסתכל ולכתוב את לחצן הבאטן מפני שהלחצן הזה הוא מוכן קיים אנחנו לא מתעסקים איתו.
אז בשביל שתהיה לנו הבנה מושגית ואמיתית מלאה לגבי מה קורה בתוך המחלקה כאשר היא מדווחת את האירוע ואיך אנחנו צריכים להירשם לאירוע כזה דרך קוד הג'אווה אנחנו צריכים לבנות מחלקה מאפס בעצמנו שמעלה אירוע ואז אנחנו צריכים גם להירשם לאירוע לתפוס אותו וברגע שנראה את שני הכיוונים האלה אז יהיה לנו הבנה מלאה לגבי מה קורה בתוך המחלקה,
למה אנחנו מחוץ למחלקה צריכים להירשם איך שאנחנו נרשמים וכך אנחנו נוכל בעצם להירשם לכל אירוע עתידי דרך קוד הג'אווה ועם הבנה מלאה מה בעצם קורה כאן. ויש המון מקרים כאלה אנחנו צריכים לעשות את זה המון פעמים בכל אפליקציה אנחנו פשוט עד היום לא נתקלנו במקרים כאלה.
לצורך כך בואו נבנה מחלקה חדשה משלנו. המחלקה שאנחנו הולכים לבנות נקראת primes manager. פריים זה מספר ראשוני, זה מספר החל משתיים ומעלה, שלם בלבד, שמתחלק רק בעצמו ובאחד, אין שום מספר אחר שמחלק אותו בלי שארית.
primes manager זאת מחלקה שהמטרה שלה זה לייצר לנו מספרים ראשוניים. אנחנו רוצים פונקציה, אנחנו רוצים לתת לפונקציה איזשהו לימיט כזה עליון, ואנחנו רוצים שהפונקציה תחזיר לנו את כל המספרים הראשונים שקיימים עד לאותו הלימיט.
ותוך כדי הבנייה נבין למה בעצם אנחנו צריכים להתעסק פה עם הקונספט של אירועים. אז בואו נבנה את הפונקציה הזאת, נרשום public arraylist integer getprimes מקבלת איזשהו int limit כלשהו.
אנחנו רוצים לרוץ ולחפש את כל המספרים הראשונים שקיימים עד הלימיט הזה, אז בואו נבנה כאן אריי ליסט שיכיל לנו את כל המספרים האלה, נקרא לו פריימס, נבנה ניו אריי ליסט ואנחנו רוצים לרוץ על כל המספרים עד לימיט כולל, בואו נרשום כאן שווה ולמעשה בגלל שהמספר הראשון
שהוא ראשוני הוא 2 אז אנחנו כבר יכולים לרוץ מ-2 ופה אנחנו רוצים לבצע איזושהי בדיקה האם ה-i הזה שאנחנו סורקים אותו כרגע הוא ראשוני כן או לא.
אם כן אנחנו רוצים לצרף אותו לפריימס. בשביל לדעת האם הוא ראשוני כן או לא בואו נבנה לנו איזושהי פונקציית עזר פרייבט כזאת בוליאן is prime.
הפונקציה תקבל איזשהו number אינטג'ר כמובן ותבדוק האם הוא ראשוני. איך אנחנו בודקים האם מספר הוא ראשוני כן או לא? קודם כל אם הnumber יותר קטן או שווה ל-1 אז המספר הוא לא ראשוני נבנה אותה עבור המקרה הכללי.
לאחר מכן אנחנו רוצים לרוץ עד ה-num לא כולל ה-num כמובן מ-2 ולבדוק האם יש איזשהו מספר שמחלק אותו. אם נע"ם מודול הוא i הוא 0 אז אנחנו רוצים גם כאן להחזיר false מפני שהוא לא יהיה ראשוני כי יש מישהו שמחלק אותו בלי שארית.
הגענו לסוף, return true כי בוודאות המספר הזה הוא מספר ראשוני וכאן אנחנו יכולים לבצע איזושהי בדיקה ולראות האם ה-i שאנחנו סורקים כרגע הוא ראשוני כן או לא.
אם כן בואו נצרף אותו לקולקשן הזה שיש לנו. בסוף הלולאה אנחנו יכולים להחזיר את פריימס. השתכפל לי פה שורה והנה יש לנו פה את הקוד המלא של המחלקה שפשוט מכילה פונקציה היא מקבלת איזשהו מספר נניח היא קיבלה 100 אז היא תחזיר את כל המספרים הראשוניים שיש עד 100 מ-2 כמובן ואנחנו נוכל להציג את המספרים האלה בלי בעיה אבל אני רוצה להוסיף עוד משהו במחלקה הזאת בכדי להבהיר
את הנקודה של למה אנחנו צריכים קודם כל כאשר אנחנו רוצים לחפש מספרים ראשונים שהם יחסית נמוכים כמו 100 כמו 1000 אולי כמו 100,000 אז זה יהיה די מהר עבור המחשב לראות האם מספר הוא מספר ראשוני כאשר הוא לא כל כך גבוה.
ברגע שאנחנו מתעסקים במספרים ראשונים מאוד גבוהים כמו מיליון או מעל מיליון אז למחשב ייקח כבר הרבה זמן וזאת הנקודה המעניינת ייקח לו הרבה זמן לדעת האם מספר הוא מספר ראשוני כי הוא פשוט צריך צריך לרוץ עד אליו וכל מספר עד אליו לבדוק את כל המספרים עד אליו האם יש מספר שמחלק אותו בלי שארית כן או לא אנחנו לא הולכים כרגע לבזבז כמות של זמן בשביל רק לבדוק את זה
אבל אנחנו כן רוצים לבצע איזושהי הדמיה כאילו שכל הסיפור הזה אכן לוקח הרבה זמן כי במציאות אם נותנים לי פה מספר גבוה זה אכן ייקח הרבה זמן אז איך אנחנו נבצע הדמיה שכל הדבר הזה לוקח הרבה זמן פשוט פקודת delay יש לנו פקודה שנקראת thread.slip בואו ניתן לה רק 100 מילי שניות והפקודה הזאת היא בעצם מבצעת delay של 100
מילי סקנדס הפקודה הזאת דורשת רק שנעטוף אותה באיזשהו try-catch כללי כזה בואו ניקח פה איזשהו exception כללי כזה כי הפקודה רק דורשת מאיתנו את זה ומה שאנחנו רוצים לעשות זה לבדוק את המחלקה הזאת אוקיי אז אנחנו רוצים שיהיה לנו פה איזשהו לחצן שפשוט מפעיל אותה.
הנה לחצן, בואו נקרא לו find primes. ניקח את הפונקציה find primes. כאן אנחנו רוצים למצוא את כל המספרים הראשוניים ולהציג אותם.
איך אנחנו מוצאים את המספרים האלה? בואו ניקח primes manager, צור אובייקט מטיפוס primes manager, ניקח איזשהו arraylist integer, ונקרא לפריימס מנאג'ר, get primes, נגיד לו הנה יש לנו פה מספר 50 ותביא לי את כל המספרים הראשונים עד 50. כמובן שאנחנו עושים הדמיה שזה ייקח טיפה
זמן, למעשה זה אמור לקחת פחות או יותר 5 שניות. אוקיי, עכשיו אנחנו רוצים להציג את המספרים האלה ולכן בואו ניגש ונבנה כאן איזשהו טקסט view, ניתן לו id text view primes, נגדיר לו טקסט סייז, נגדיר לו גראביטי כדי שהוא יהיה כזה יפה באמצע אנחנו רוצים לקחת
ולאתר את הרכיב הזה טקסט view טקסט view primes הנה הוא פיינד view iid טקסט view primes יש לנו אותו ועכשיו אנחנו יכולים פשוט לרוץ עליו בלולאה למעשה לרוץ על כל המספרים הראשונים primes.size וכל אחד מהם לגשת לטקסט view primes ופשוט לבצע איזשהו append ולהוסיף אליו את כל המספרים
אנחנו רוצים להוסיף אליו את primes get תביא לי בבקשה את הפריט ה-i תעשה פה איזשהו שרשור של רווח אולי לפני שנעשה את זה ניגש ונבצע סט טקסט ונרוקן אותו מתוכן קודם ואפילו בואו נעשה עוד איזשהו שירות ניגש לאקטיביטי ובאון קליק על האקטיביטי נבצע קליר דיספליי.
זאת אומרת אם היוזר גם לוחץ קליק על האקטיביטי אז אנחנו רוצים לאפס ולרוקן את הטקסט view primes הזה. סט טקסט אז בעצם כשלוחצים על הלחצן find primes אנחנו ניגשים למחלקה יוצרים ממנה אובייקט קוראים לפונקציה get primes אומרים לה הנה מספר תביא
לי את כל המספרים הראשונים שקיימים עד המספר הזה ופשוט אנחנו מציגים אותה. בואו נריץ, בואו נלחץ על הלחצן ועכשיו אנחנו רואים שלוקח לו את הזמן שלו, למעשה זה לוקח 5 שניות ורק בסיום הזמן הזה שהמחלקה סיימה פתאום אנחנו רואים את כל המספרים.
אוקיי, מגניב. בואו נלחץ כאן איפשהו על האקטיביטי בשביל לנקות את זה ושוב פעם אנחנו לוחצים אנחנו רואים שהלחצן בעצם תקוע כי הוא עובד קשה ברקע ואחרי 5 שניות הכל בסדר ואנחנו רואים את התוצאה.
מה שמעניין אותנו לראות כאן זה שהייתה פה איזושהי פעילות פנימית בתוך המחלקה שלקחה זמן ורק בסיום שלה היא בעצם סיימה והחזירה לנו איזושהי תוצאה.
זה מעולה אנחנו רוצים את התוצאה בסיום אבל אולי אנחנו רוצים גם תוך כדי הפעילות הפנימית הזאת שלוקחת זמן אנחנו גם רוצים לדעת מה בעצם קורה שם אנחנו רוצים אולי כל פעם שנמצא מספר ראשוני לדעת מזה אבל מי זה אנחנו?
הרי אם אנחנו המחלקה, אז אנחנו יודעים תוך כדי הלולאה מתי בכל רגע ורגע נמצא מספר ראשוני, מתי זה קרה בדיוק פה בתוך ה-if. אבל אם אנחנו לא בתוך המחלקה,