במהלך השיעורים הקודמים, לימדנו אתכם מהם רכיבים גראפיים, כיצד למקם אותם על המסך ולעבוד איתם דרך הקוד. השבוע אנחנו משלימים את הנושא על ידי התייחסות לנושא חדש – ארועים (או Events בשמם הלועזי).
אז מה הם בעצם "ארועים"?
ארועים הם דרכם של רכיבים לספר לנו שמשהו בעצם קרה, ולתת לנו את ההזדמנות להגיב לכך.
דוגמא לכך היא למשל רכיב מסוג כפתור (Button) המודיע לנו שמישהו לחץ עליו. דוגמא נוספת היא שרכיב מסוג תיבת טקסט (EditText) מודיע לנו שהמשתמש הקיש בתוכו תו מסויים. רכיבים גראפיים מכילים ארועים רבים שאנחנו יכולים להאזין להם.
Interface (ממשק)
רגע לפני שנסביר כיצד מבצעים את זה, בואו ניתן סקירה לאלו מכם שאינם ותיקים בתחום התיכנות אודות נושא ה- Interfaces (ממשקים) בשפת Java וכיצד יש להשתמש בהם.
אחת הדרכים הטובות והפשוטות להעביר נושא זה, היא באמצעות סיפור.
פעם היה בחור בשם יקותיאל. יקותיאל היה תוכניתן ומעצב גראפי שעלה על רעיון חדש וגאוני ליצור כפתור חדש שאפשר להשתמש בו בתוכנות שונות.
הכפתור היה שונה מכל כפתור שאי פעם ראיתם. היה לו עיצוב גראפי יחודי והוא סיפק מתודות משוכללות וחדשות ביותר.
יקותיאל כתב את הקוד לכפתור הזה והחליט שהוא כל כך מוצלח! שהוא רוצה למכור אותו דרך האינטרנט ולעשות מליונים! הוא קרא לכפתור שלו SuperButton.
כאשר לוחצים על הכפתור של יקותיאל, יקותיאל רוצה להכריז לאפליקציה שמשתמשת בכפתור שלו "לחצו עלי!!", כדי שהאפליקציה תוכל להגיב בהתאם.
הבעיה של יקותיאל היתה שהוא עדיין לא מכיר אף אחד מהאנשים או מהתוכנות שישתמשו בכפתור שלו ולא יכל ליזום בעצמו קריאה למתודות שלהם, בכל פעם שלוחצים עליו.
מה שהיה חסר בעצם ליקותיאל זה בעצם הגדרה של Interface, שמאפשרת לו לסכם מראש על מתודה אליה הוא יקרא תמיד, לאחר לחיצה על הכפתור.
Interface, או "ממשק", הוא כלי רב עוצמה שמאפשר למחלקות שלא מכירות אחת את השניה להגדיר ביניהן "חוזה" בו צד ב' מתחייב לממש מתודה מסויימת וצד א' מתחייב לקרוא לה בשלב מסויים.
ממשק כולל הצהרה של כל המתודות, שהמחלקה שתממש אותו חייבת לממש.
בצורה כזאת גם אם הכפתור של יקותיאל לא מכיר את התוכנה שעומדת לממש אותו, הוא עדיין יכול לדעת שבטוח היא תממש את הממשק שסוכם עליו.
הגדרת Interface
כדי להגדיר ממשק אנחנו צריכים בעצם להצהיר על כל המתודות שמופיעות בו.
ממשק יכול להכיל אך ורק הצהרה על מתודות, בלי המימוש שלהן, אשר אותו צריכה להוסיף המחלקה שתממש אותו.
זהו סוג של מִתְאָר של הסעיפים בחוזה.
בואו ונראה דוגמא:
הגדרה של Interface בשם OnDoubleClickListener
public interface OnDoubleClickListener {
public void onClick();
}
הגדרנו interface חדש בשם OnDoubleClickListener המכיל הגדרה של מתודה אחת בשם onClick.
בעצם כאשר לוחצים על הכפתור של יקותיאל פעמיים (Double Click), תבוצע קריאה יזומה למתודה בשם הזה.
שימו לב גם לכך שהגדרת interface מתחילה במשפט public interface ולא במשפט public class.
public class SuperButton {
private OnDoubleClickListener myListener;
public void setOnClickListener(OnDoubleClickListener Listener) {
myListener = Listener;
}
public void someMethod() {
if (myListener != null)
myListener.onClick();
}
}
זאת בעצם ההגדרה של המחלקה המיוחדת של יקותיאל, SuperButton. המימוש עצמו של המחלקה לא משנה להסבר הנוכחי שלנו ולכן הוא לא כתוב פה בכלל והמחלקה נראית ריקה.
מה שמאד מעניין הוא השורות הבאות:
שורה 02: הגדרה של משתנה בשם myListener מסוג DoubleClickListener. המשתנה בעצם יכול להכיל כל עצם אחר, אשר מממש את המתודה (או המתודות, במקרה אחר) שהוגדרו בה- Interface שלנו OnDoubleClickListener.
שורות 04-06: הגדרה של מתודה בשם setOnClickListener המקבלת כפרמטר מחלקה המממשת את DoubleClickListener ומזינה אותה לתוך myListener. בעצם כל מחלקה מחוץ לכפתור המיוחד של יקותיאל יכולה לקרוא למתודה הזאת ולהעביר כפרמטר כל מחלקה אשר מממשת את המתודות שנמצאות בתוך DoubleClickListener.

זאת הערה מאד חשובה ונכונה פרופסור. בעצם המהדר "אוכף" את החוק ומחייב את מי שמממש Interface, לממש את כל המתודות שבתוכו. נסו לא לממש אותן ותראו שתקבלו שגיאה.
להלן דוגמא למחלקה שמממשת את OnDoubleClickListener
public class UnknownClass implements OnDoubleClickListener {
@Override
public void onClick() {
// ..some code...
// ..some code...
}
}
בעצם את כל המחלקה UnknownClass אפשר להעביר כפרמטר למתודה SetOnClickListener בתוך SuperButton, והיא כבר תדאג לקרוא ל- onClick שנמצאת בתוכה וזאת תוך ידיעה ודאית ש- onClick ממומש.
סיכום Interfaces
השימוש ב- Interfaces הינו נפוץ ושימושי ביותר, ובעזרתו אנחנו יכולים למשל להתחבר לכל הארועים שמתרחשים ברכיבים הגראפיים השונים (כפתורים, תיבות טקסט, טבלאות וכל רכיב גראפי אחר). ישנם שימושים רבים אחרים לממשקים, אבל לא נדון עליהם בשיעור זה.
ארועים (Events)
חזרה לנושא שהתמקדנו בו בתחילת השיעור. הרכיבים הגראפיים השונים באנדרואיד מכילים ארועים שונים להם אנחנו יכולים "להאזין" ולפעול, כאשר הם מתרחשים. הארועים פועלים באמצעות ממשקים, וכדי להאזין להם, נצטרך לממש Interface ומתודות הקשורות אליהם.
לשם הדוגמא, אנו ניצור פרויקט חדש ובו שני רכיבים גראפיים, תיבת טקסט (EditText) וכפתור (Button).
EditText ישמש אותנו כתיבה רגילה לכתיבת טקסט.
Button ישמש אותה בכך שכאשר נלחץ עליו, הטקסט שבתוכו ישתנה לפי מה שכתוב בתוך ה- EditText.
לשני הרכיבים יש מגוון ארועים שונים שהם מדווחים עליהם, אבל לשם ההדגמה נתרכז רק בארוע הלחיצה של Button.
Button
כדי להאזין לארוע שמתרחש בכל פעם שהמשתמש לוחץ על הכפתור, אנו צריכים לממש Interface בשם View.OnKeyListener (כלומר, ה- Interface נמצא בתוך המחלקה View ולכן שמה מופיע קודם) ולאחר מכן לממש מתודה בשם onClick (אל תשכחו שברגע שממשתם Interface בעצם "חתמתם על חוזה" ואתם מחוייבים לממש את המתודות שלו).
כמובן שאנחנו נצטרך ללכת לעצם שלנו ולהגיד לו שאנחנו מאזינים לו. נדגים זאת מיד.
יאללה לעבודה
צרו פרוייקט חדש באנדרואיד, ובממשק המשתמש הוסיפו רכיב מסוג EditText ומתחתיו רכיב מסוג Button. קובץ ה- xml של המסך צריך להראות בסוף כך:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFF"> <EditText android:text="" android:id="@+id/EditText01" android:layout_width="wrap_content" android:layout_height="wrap_content"></EditText> <Button android:text="" android:id="@+id/Button01" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout>
הכנסו לקובץ ה- Activity המרכזי שלכם, והוסיפו בשורת הגדרת המחלקה מימוש ל- Interfaces שתיארתי לעיל (View.OnKeyListener, View.OnClickListener). שורת הקוד צריכה להראות כך:
public class GUI extends Activity implements View.OnClickListener {
זאת כמובן בתנאי ששם המחלקה היא באמת GUI, אחרת יופיע לכם שם אחר.
אתם יכולים לראות שישר אחרי שהגדרתם את המחלקה, ה- Eclipse ישים לכם X אדום בשורה שלהם ויתריע לכם שמשהו לא בסדר. כפי שציינתי מקודם, הבעיה היא שממשנו שני Interfaces (כלומר שני "חוזים") אבל לא מימשנו את המתודות שהוגדרו בתוכם. לחיצה אחת על ה- X האדום תקפיץ תפריט שיקל לכם על העבודה ויאפשר לכם לבחור "add unimplemented methods", כלומר "הוסף מתודות חסרות". ביחרו באפשרות זו.
מיד תוכלו לראות שה- Eclipse הוסיף לכם אוטומטית את המתודות onKey ו- onClick.
כעת כל מה שצריך לעשות הוא ללכת לרכיבים עצמם ולהגיד להם שאנחנו מאזינים להם.
לאחר מכן יש כמובן להוסיף את הלוגיקה הרצויה לתוך המתודות.
להלן קטע הקוד המלא:
package iAndroid.GUI;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class GUI extends Activity implements View.OnClickListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button myButton = (Button)findViewById(R.id.Button01);
myButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
EditText myEditText = (EditText)findViewById(R.id.EditText01);
Button myButton = (Button)v;
myButton.setText(myEditText.getText());
}
}
בואו נעבור על השורות החשובות בקטע הקוד הזה:
שורה 9: הגדרת המחלקה ומימוש ה- Interfaces. כבר דיברנו על כך לעיל.
שורה 16: מציאת הכפתור שלנו מתוך ה- Resource
שורה 17: קריאה למתודה setOnClickListener אשר מקבלת פרמטר אחד, והוא מחלקה אשר מממשת את ה- Interface (ה- "חוזה") onClick. גם כאן אנחנו מעבירים את this כי מחלקת GUI מממשת אותו.
שורות 33 עד 37: מתודת onClick שרצה לאחר שמשתמש לחץ על הכפתור. בקצרה, הקוד בעצם משנה את טקסט של הכפתור לטקסט הרשום בתוך תיבת הטקסט.
הריצו את הקוד, כנסו לתיבת הטקסט והקישו מספרים ואותיות. לאחר מכן ליחצו על הכפתור וראו מה קורה
סיכום ארועים (Events)
השיעור למדנו מה הם Interfaces, מה הם ארועים (Events) וכיצד ניתן להאזין להם ולהגיב בהתאם.

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

תגובות
השאר תגובה טראקבאקים