
SurfaceView. מעבירים אליה מ-MainActivity את השדות SurfaceHolder ו-Camera (כשדות פרטיים) ואת פעולות האתחול, שנכנסות לקונסטרקטור. במקום אובייקט SurfaceView קוראים ל-getHolder() של המחלקה עצמה.Context ו-AttributeSet, כלומר את האטריבוטים שהוגדרו ב-XML (רוחב, גובה, ID ועוד), ולהעביר אותם ל-super.SurfaceHolder.Callback, והקוד של surfaceCreated (פתיחת המצלמה ותצוגה מקדימה) ושל surfaceDestroyed (שחרור המצלמה) עובר אליה. MainActivity נשארת כמעט ריקה.OnErrorListener עם onError(IOException), שדה פרטי ופונקציה setOnErrorListener. בתוך ה-catch קוראים ל-onError רק אם ה-Listener אינו null.SurfaceView בתגית עם השם המלא של המחלקה (כולל החבילה) ובאותו ID. ב-MainActivity מאתרים את הרכיב, קוראים ל-setOnErrorListener ו-MainActivity מממשת את הממשק ומציגה Toast.surfaceCreated עלול לרוץ מיד כשהאפליקציה עולה, לפני ש-setOnErrorListener נקרא. אם אז תהיה שגיאה, ה-Listener יהיה null והדיווח לא יגיע. אפשר גם לכתוב ללוג או להציג הודעה בתוך ה-catch.הטקסט המלא של הדקות הראשונות בהרצאה «מצלמה - חלק 4 - צילום מתוך האפליקציה - המשך» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
אחרי שראינו איך ה-surface view פועל יהיה נכון להוציא את כל הקוד שכתבנו למחלקה נפרדת שתטפל בכל הנושא של ה-surface view. כאילו שאנחנו הולכים לבנות רכיב ויזואלי חדש ולהציב את הרכיב הזה על ה-layout.
זה יהיה בעצם דיזיין יותר נכון כי אז אנחנו מפרידים את כל הפונקציונליות הזאת של הקאמרה לרכיב חיצוני ומשחררים את ה-main activity לבצע את הקוד שלה שלא קשור ל-surface view שאנחנו בונים.
אז בואו נצרף מחלקה חדשה ובואו נקרא לה camera surface view ואנחנו רוצים to extend את ה-surface view כי אנחנו בעצם רוצים להגדיר שאנחנו רכיב ה-surface view ואנחנו מתפקדים בדיוק באותו אופן שמקודם תפקדנו רק שהקוד מקודם היה בתוך המיין אקטיביטי.
אז בואו ניגש למיין אקטיביטי ונתחיל להעתיק את המידע למחלקה שאנחנו בונים. אז אנחנו א', לא צריכים surface view, בואו פשוט נמחק את זה ואנחנו רוצים שיהיה בתוך המחלקה שאנחנו בונים את ה-surface holder ואת הקאמרה.
אז נעתיק אותם כאן כ-data members, בצורת פרייבט כאלה בואו ניפטר מהקוד הזה אוקיי אנחנו רואים שיש לנו פה איזה שהם שתי פעולות חול אז בואו נעתיק את הפעולות האלה ונדביק אותם בקונסטרקטור שאנחנו צריכים לבנות כאן בואו נבנה כאן public camera surface view קונסטרקטור ופשוט נדביק את שני החבר'ה האלה כאן אבל בגלל שאנחנו בעצמנו Surface View אז אנחנו יכולים
למחוק את האובייקט הזה ופשוט לקרוא לפונקציה Get Holder שהיא שלנו. עכשיו נקודה מאוד חשובה ומאוד מעניינת. אם אנחנו בונים רכיב ויזואלי שאנחנו רוצים להציב אותו על Layout במקום ה-Surface View שמקודם הצבנו כאן, אם אנחנו עושים דבר כזה אז אנחנו צריכים לבנות קונסטרקטור שמקבל שני משתנים,
קונטקסט, איזה קונטקסט הלייאוט שייך לו, ואטריביוט סט. זה בעצם אובייקט שמתאר את האטריביוטס השונים שאנחנו רואים כאן.
אנחנו רואים פה כל מיני אטריביוטס שמועברים לרכיב הוויזואלי. ומה שקורה זה שברגע ששמים רכיב ויזואלי, או אדי טקסט או טקסט ויו או סרפייס ויו או כל רכיב ויזואלי ששמים אותו על גבי ליהאוט אז אנחנו יודעים כמובן שמוגדרים לרכיב הזה כל מיני אטריביוטס הגדרנו וויד הגדרנו הייט הגדרנו איידי הגדרנו
טקסט מלא אטריביוטס שונים כל האטריביוטס האלה נשלחים לקונסטרקטור של הרכיב שמקבל קונטקסט ואת האטריביוטס ואנחנו צריכים להעביר את זה למחלקת הבסיס שלנו לסופר אז בואו ניגש לסופר נעביר את הקונטקסט את האטריביוט סט ועכשיו גם אנחנו יכולים להיות רכיב ויזואלי ולהציב את עצמנו על גבי הלאוט.
אוקיי הדבר הבא שאנחנו רואים כאן זה שיש לנו את הדיס הזה שאומר שאנחנו בתור רכיב ממשים את האינטרפייס שמקודם מימשנו במיין אקטיביטי אז בואו נלחץ כאן על אלט אנטר ונגדיר make camera surface view אימפלמנט את הקולבאק הזה, נוריד את הדירקטיב, נגדיר לו אוקיי,
והנה אנחנו רואים שאנחנו מממשים את ה-surface view, את ה-surface holder, סליחה, נקודה, קולבאק, והנה שלושת הפונקציות שמקודם מימשנו במיין אקטיביטי, אז בואו נחזור למיין אקטיביטי, ואפשר להיפטר עכשיו מההורשה הזאת, מה-implementation הזה, ואפשר להיפטר מכל הקוד הזה,
כל הקוד הזה פשוט נוציא ונשים את זה כאן בתוך הסרפייס קריאטד ויש לנו פה את הקאמרה ריליס נעתיק נדביק אותו לפה אנחנו יכולים לחזור למיין אקטיביטי ולהיפטר משלושת הרכיבים האלה שלושת הפונקציות האלה למעשה שימו לב שהמיין אקטיביטי כרגע היא מאוד ריקה כי אנחנו הוצאנו פשוט את כל מה שלא קשור ישירות למיין אקטיביטי
אלא לרכיב ויזואלי הוצאנו את זה למחלקה חיצונית, לא עשינו מעבר לזה שום דבר מיוחד אחר. עכשיו יש לנו פה בעיה עם הטוסט, ובאמת אנחנו לא אמורים להציג טוסטים אם אנחנו ברכיב ויזואלי חיצוני.
אז בואו נעשה מה שתמיד עשינו כשיש את הבעיה הזאת, וזה היה לדווח אירוע על ידי ליסנר מתאים. אז בואו נבנה פה אינטרפייס ונקרא לו onErrorListener ונגדיר פה איזושהי פונקציה, נקרא לה on-error והפונקציה הזאת היא תקבל איזשהו exception למעשה ה-exception היחידי זה ה-ioexception שאנחנו רואים כאן אז בואו פשוט נגדיר ioexception היא x וכעת אנחנו
רוצים לבנות את המנגנון של הליסנר בואו כבר נזכר איך עושים את זה מעבר לאינטרפייס אנחנו רוצים לבנות כאן אובייקט פרייבט מסוג on-error listener בואו נקרא לו פשוט listener, בואו נבנה פונקציה public void set on error listener שמקבלת listener כזה ופשוט שמה אותו
בתוך אובייקט ה-listener הגלובלי ואז אנחנו יכולים כאן לא להציג את ההודעה בתוך רכיב נפרד אלא פשוט לדווח במידה וה-listener שונה מנ"ל זאת אומרת אם מישהו אכן רוצה לקבל את הדיווח הזה אז אנחנו קוראים לליסנר נקודה on-error ופשוט שולחים לו את האקספצ'ן ומי שרוצה שיציג את זה
מבחוץ אנחנו לא מציגים הודעות שגיאה בתוך. עכשיו שימו לב רק לנקודה אחת שחשוב לציין שיכול להיות שה-surface created תתבצע לפני שנספיק להכניס איזשהו ליסנר לתוך הפונקציה.
למה? כי אנחנו הולכים לשים את הרכיב שלנו על ה-Layout, אז יכול להיות שאיך שהאפליקציה תתבצע, או ליתר דיוק תרוץ, אוטומטית ייווצר רכיב ה-Camera Surface View על גבי ה-Layout, אוטומטית יתבצע הקונסטרקטור שלו וכל ה-Surface Holder יירשם לאירוע.
שלושת הפונקציות האלה, Surface Created, Surface Change ו-Surface Destroyed יהיו קיימות. מיידית תתבצע בקיצור כאשר האפליקציה עולה בלי שאף אחד שלח listener לתוך הפונקציה set on error listener כלומר לא הספיקו לעשות את זה ואז בוא נניח שתתבצע איזושהי שגיאה המערכת לא תצליח לעשות preview במכשיר
או לא תצליח למצוא קאמרה או משהו כזה אוטומטית תתבצע שגיאה אבל ה-listener יהיה נעל אז יש צורך אולי גם לרשום פה איזושהי פקודה לתוך הלוג אז רק