אפליקציות ל-Android שולחות ומקבלות הודעות שידור ממערכת Android ומאפליקציות אחרות ל-Android, בדומה לדפוס העיצוב פרסום-הרשמה. בדרך כלל, המערכת והאפליקציות שולחות שידורים כשאירועים מסוימים מתרחשים. לדוגמה, מערכת Android שולחת שידורים כשמתרחשים אירועים שונים במערכת, כמו הפעלת המערכת או טעינה של המכשיר. אפליקציות שולחות גם שידורים מותאמים אישית, למשל כדי להודיע לאפליקציות אחרות על משהו שעשוי לעניין אותן (למשל, הורדת נתונים חדשים).
אפליקציות יכולות להירשם כדי לקבל שידורים ספציפיים. כשמשדרים שידור, המערכת מפנה אותו באופן אוטומטי לאפליקציות שנרשמו לקבלת סוג השידור הספציפי הזה.
באופן כללי, אפשר להשתמש בשידורים כמערכת להעברת הודעות בין אפליקציות ומחוץ לתהליך הרגיל של משתמש. עם זאת, חשוב להיזהר שלא לנצל לרעה את ההזדמנות להגיב לשידורים ולהריץ משימות ברקע שעלולות לגרום לביצועים איטיים של המערכת.
מידע על שידורי מערכת
המערכת שולחת שידורים באופן אוטומטי כשמתרחשים אירועים שונים במערכת, למשל כשהמערכת עוברת למצב טיסה וממנו. כל האפליקציות שנרשמו לקבלת עדכונים מקבלות את השידור הזה.
האובייקט Intent
עוטף את הודעת השידור. המחרוזת action
מזהה את האירוע שהתרחש, למשל android.intent.action.AIRPLANE_MODE
. הכוונה עשויה לכלול גם מידע נוסף שמצורף לשדה הנוסף שלה.
לדוגמה, הכוונה למצב טיסה כוללת פרמטר בווליאני שמציין אם מצב הטיסה מופעל או כבוי.
מידע נוסף על קריאת כוונות ועל אחזור מחרוזת הפעולה מכוונת מפורט במאמר כוונות ומסנני כוונות.
פעולות של שידורי מערכת
רשימה מלאה של פעולות השידור במערכת מפורטת בקובץ BROADCAST_ACTIONS.TXT
ב-Android SDK. לכל פעולת שידור יש שדה קבוע שמשויך אליה. לדוגמה, הערך של הקבוע ACTION_AIRPLANE_MODE_CHANGED
הוא android.intent.action.AIRPLANE_MODE
.
מסמכי התיעוד של כל פעולת שידור זמינים בשדה הקבוע המשויך אליה.
שינויים בשידורי המערכת
ככל שפלטפורמת Android מתפתחת, היא משתנה מדי פעם באופן שבו השידור של המערכת מתנהל. חשוב לשים לב לשינויים הבאים כדי לתמוך בכל הגרסאות של Android.
Android 16
ב-Android 16, לא ניתן להבטיח את סדר השליחה של שידורים באמצעות המאפיין android:priority
או IntentFilter.setPriority()
בתהליכים שונים. המערכת מתייחסת לעדיפויות השידור רק באותו תהליך של בקשת הבקשה, ולא בכל התהליכים.
בנוסף, תעדוף השידור מוגבל באופן אוטומטי לטווח (SYSTEM_LOW_PRIORITY
+ 1, SYSTEM_HIGH_PRIORITY
- 1).
רק רכיבי מערכת יכולים להגדיר את הערכים SYSTEM_LOW_PRIORITY
ו-SYSTEM_HIGH_PRIORITY
כעדיפות שידור.
Android 14
כשאפליקציות נמצאות במצב שמאוחסן במטמון, המערכת מבצעת אופטימיזציה של העברת השידור כדי לשמור על תקינות המערכת. לדוגמה, המערכת דוחה שידורי מערכת פחות חשובים כמו ACTION_SCREEN_ON
בזמן שהאפליקציה נמצאת במצב שמאוחסן במטמון.
אחרי שהאפליקציה עוברת ממצב השמירה במטמון למחזור חיים של תהליך פעיל, המערכת שולחת את כל השידורים שנדחו.
שידורים חשובים שמוצהרים במניפסט מסירים באופן זמני אפליקציות מהמצב ששמור במטמון לצורך העברה.
Android 9
החל מגרסה 9 של Android (רמת API 28), ההודעה NETWORK_STATE_CHANGED_ACTION
לא מקבלת מידע על המיקום של המשתמש או על פרטים אישיים מזהים.
אם האפליקציה מותקנת במכשיר עם Android 9.0 (רמת API 28) ואילך, המערכת לא כוללת את מזהי ה-SSID, מזהי ה-BSSID, פרטי החיבור או תוצאות הסריקה בשידורי Wi-Fi. כדי לקבל את המידע הזה, צריך להתקשר למספר getConnectionInfo()
במקום זאת.
Android 8.0
החל מגרסה Android 8.0 (רמת API 26), המערכת מטילה הגבלות נוספות על מקלטי הודעות שהוגדרו במניפסט.
אם האפליקציה שלכם מטרגטת ל-Android בגרסה 8.0 ואילך, אי אפשר להשתמש במניפסט כדי להצהיר על מקלט לרוב השידורים המשתמעים (שידורים שלא מטרגטים את האפליקציה שלכם באופן ספציפי). עדיין אפשר להשתמש במקלט שמירשם לפי הקשר כשהמשתמש משתמש באפליקציה באופן פעיל.
Android 7.0
בגרסה Android 7.0 (רמת API 24) ואילך, לא נשלחים שידורי המערכת הבאים:
בנוסף, אפליקציות שמטרגטות את Android מגרסה 7.0 ואילך צריכות לרשום את השידור של CONNECTIVITY_ACTION
באמצעות registerReceiver(BroadcastReceiver, IntentFilter)
. הצהרה על מקלט במניפסט לא עובדת.
קבלת שידורים
אפליקציות יכולות לקבל שידורים בשתי דרכים: באמצעות מקלטים שמתועדים בהקשר ומקלטים שמוצהרים במניפסט.
נמענים שנרשמו בהקשר
מקלטים שמתועדים לפי הקשר מקבלים שידורים כל עוד ההקשר שלהם בתוקף. בדרך כלל, הזמן הזה הוא בין הקריאות ל-registerReceiver
ול-unregisterReceiver
. ההקשר של הרישום הופך ללא תקף גם כשהמערכת משמידה את ההקשר התואם. לדוגמה, אם נרשמים בהקשר של Activity
, מקבלים שידורים כל עוד הפעילות פעילה. אם תירשמו באמצעות ה-Application context, תקבלו שידורים כל עוד האפליקציה פועלת.
כדי לרשום מקלט עם הקשר, מבצעים את השלבים הבאים:
בקובץ ה-build ברמת המודול של האפליקציה, צריך לכלול את הגרסה 1.9.0 ואילך של ספריית הליבה של AndroidX:
Groovy
dependencies { def core_version = "1.16.0" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.1.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0-beta02" }
Kotlin
dependencies { val core_version = "1.16.0" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.1.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0-beta02") }
יוצרים מופע של
BroadcastReceiver
:Kotlin
val myBroadcastReceiver = MyBroadcastReceiver()
Java
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
יוצרים מופע של
IntentFilter
:Kotlin
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
Java
IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
בוחרים אם לייצא את מקלט השידור ולהפוך אותו גלוי לאפליקציות אחרות במכשיר. אם המקלט הזה מקשיב לשידורים שנשלחים מהמערכת או מאפליקציות אחרות – גם מאפליקציות אחרות שבבעלותכם – צריך להשתמש בדגל
RECEIVER_EXPORTED
. אם המקלט הזה מקשיב רק לשידורים שנשלחים מהאפליקציה, צריך להשתמש בדגלRECEIVER_NOT_EXPORTED
.Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }
Java
boolean listenToBroadcastsFromOtherApps = false; int receiverFlags = listenToBroadcastsFromOtherApps ? ContextCompat.RECEIVER_EXPORTED : ContextCompat.RECEIVER_NOT_EXPORTED;
מחייבים את המכשיר המקבל למספר
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
כדי להפסיק לקבל שידורים, צריך להתקשר למספר
unregisterReceiver(android.content.BroadcastReceiver)
. חשוב לבטל את הרישום של המקלט כשלא צריכים אותו יותר או שההקשר כבר לא תקף.
ביטול הרישום של מקלט השידור
בזמן שהמקלט של השידור רשום, הוא מכיל הפניה ל-Context שבו רשמתם אותו. מצב כזה עלול לגרום לדליפות אם ההיקף הרשום של הנמען חורג מהיקף מחזור החיים של ההקשר. לדוגמה, זה יכול לקרות כשרושמים מקלט ברמת הפעילות, אבל שוכחים לבטל את הרישום שלו כשהמערכת משמידה את הפעילות. לכן, תמיד צריך לבטל את הרישום של מקלט השידור.
Kotlin
class MyActivity : ComponentActivity() {
private val myBroadcastReceiver = MyBroadcastReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
setContent { MyApp() }
}
override fun onDestroy() {
super.onDestroy()
// When you forget to unregister your receiver here, you're causing a leak!
this.unregisterReceiver(myBroadcastReceiver)
}
}
Java
class MyActivity extends ComponentActivity {
MyBroadcastReceiver myBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
// Set content
}
}
רישום של מקלטים בהיקף הקטן ביותר
צריך לרשום את מקלט השידור רק כשבאמת רוצים לקבל את התוצאה. בוחרים את היקף הנמען הקטן ביותר האפשרי:
- שיטות מחזור החיים
LifecycleResumeEffect
אוonResume
/onPause
של הפעילות: מקלט השידור מקבל עדכונים רק כשהאפליקציה נמצאת במצב שבו היא ממשיכה לפעול. - שיטות מחזור החיים
LifecycleStartEffect
אוonStart
/onStop
של הפעילות: מקלט השידור מקבל עדכונים רק כשהאפליקציה נמצאת במצב שבו היא ממשיכה לפעול. DisposableEffect
: מקלט השידור מקבל עדכונים רק בזמן שהרכיב הניתן ליצירה נמצא בעץ היצירה. ההיקף הזה לא מצורף להיקף של מחזור החיים של הפעילות. מומלץ לרשום את הנמען בהקשר של האפליקציה. הסיבה לכך היא שבאופן תיאורטי, הרכיב הניתן לקיבוץ יכול לחיות מעבר להיקף מחזור החיים של הפעילות ולגרום לדליפת הפעילות.- פעילות
onCreate
/onDestroy
: מקלט השידור מקבל עדכונים בזמן שהפעילות נמצאת במצב היצירה שלה. חשוב לבטל את ההרשמה ב-onDestroy()
ולא ב-onSaveInstanceState(Bundle)
, כי יכול להיות שהפונקציה הזו לא תופעל. - היקף מותאם אישית: לדוגמה, אפשר לרשום מקלט בהיקף
ViewModel
כדי שהוא ישרוד את יצירת הפעילות מחדש. חשוב להשתמש בהקשר של האפליקציה כדי לרשום את המקבל, כי המקבל יכול לחיות מעבר להיקף מחזור החיים של הפעילות ולגרום לדליפת הפעילות.
יצירת רכיבים מורכבים עם מצב ורכיבים מורכבים ללא מצב
ב-Compose יש רכיבים מורכבים עם מצב ורכיבים מורכבים ללא מצב. רישום או ביטול רישום של מקלט שידורים בתוך רכיב מורכב הופכים אותו למצבי. הרכיב הקומפוזיבי הוא לא פונקציה גורמית שמרינדרת את אותו תוכן כשמקבלים את אותם פרמטרים. המצב הפנימי יכול להשתנות בהתאם לקריאות למכשיר הרשום לקבלת השידור.
שיטה מומלצת ב-Compose היא לפצל את הרכיבים הניתנים לקישור לגרסאות עם שמירת מצב ולגרסאות ללא שמירת מצב. לכן מומלץ להוציא את היצירה של מקלט השידור מ-Composable כדי להפוך אותו ללא מצב:
@Composable
fun MyStatefulScreen() {
val myBroadcastReceiver = remember { MyBroadcastReceiver() }
val context = LocalContext.current
LifecycleStartEffect(true) {
// ...
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
}
MyStatelessScreen()
}
@Composable
fun MyStatelessScreen() {
// Implement your screen
}
מקלטים שצוינו במניפסט
אם תצהירו על מקלט שידור במניפסט, המערכת תפעיל את האפליקציה כשהשידור יישלח. אם האפליקציה לא פועלת, המערכת תפעיל אותה.
כדי להצהיר על מקלט שידור במניפסט:
מציינים את הרכיב
<receiver>
במניפסט של האפליקציה.<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.example.snippets.ACTION_UPDATE_DATA" /> </intent-filter> </receiver>
מסנני ה-Intent מציינים את פעולות השידור שהמקלט שלכם נרשם אליהן.
יוצרים מחלקה משנית של
BroadcastReceiver
ומטמיעים אתonReceive(Context, Intent)
. מקלט השידור בדוגמה הבאה מתעד ביומן את תוכן השידור ומציג אותו:Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var dataRepository: DataRepository override fun onReceive(context: Context, intent: Intent) { if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") { val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data" // Do something with the data, for example send it to a data repository: dataRepository.updateData(data) } } }
Java
public static class MyBroadcastReceiver extends BroadcastReceiver { @Inject DataRepository dataRepository; @Override public void onReceive(Context context, Intent intent) { if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) { String data = intent.getStringExtra("com.example.snippets.DATA"); // Do something with the data, for example send it to a data repository: if (data != null) { dataRepository.updateData(data); } } } }
מנהל החבילות של המערכת רושם את המקלט כשהאפליקציה מותקנת. לאחר מכן, המקלט הופך לנקודת כניסה נפרדת לאפליקציה, כך שהמערכת יכולה להפעיל את האפליקציה ולספק את השידור אם האפליקציה לא פועלת.
המערכת יוצרת אובייקט רכיב חדש מסוג BroadcastReceiver
כדי לטפל בכל שידור שהיא מקבלת. האובייקט הזה תקף רק למשך הקריאה ל-onReceive(Context, Intent)
. אחרי שהקוד חוזר מהשיטה הזו, המערכת מתייחסת לרכיב כאל רכיב לא פעיל.
השפעות על מצב התהליך
המצב של BroadcastReceiver
(פעיל או לא פעיל) משפיע על התהליך שהוא מכיל, ויכול לשנות את הסבירות שהוא יהרוג את המערכת. תהליך בחזית מבצע את השיטה onReceive()
של הנמען. המערכת מפעילה את התהליך, אלא אם יש מחסור קיצוני בזיכרון.
המערכת משביתה את BroadcastReceiver
אחרי onReceive()
.
המשמעות של תהליך המארח של המקבל תלויה ברכיבי האפליקציה שלו. אם התהליך הזה מארח רק מקלט שהוצהר במניפסט, המערכת עשויה להרוג אותו אחרי onReceive()
כדי לפנות משאבים לתהליכים קריטיים יותר. המצב הזה נפוץ באפליקציות שהמשתמש לא נכנס אליהן אף פעם או לא נכנס אליהן לאחרונה.
לכן, מכשירי מקלט של שידורים לא צריכים להתחיל שרשראות ארוכות ברקע.
המערכת יכולה להפסיק את התהליך בכל שלב אחרי onReceive()
כדי לפנות זיכרון, וכך לסיים את השרשור שנוצר. כדי שהתהליך ימשיך לפעול, צריך לתזמן אירוע JobService
מהמקלט באמצעות JobScheduler
כדי שהמערכת תדע שהתהליך עדיין פועל. פרטים נוספים זמינים במאמר סקירה כללית על עבודות רקע.
שליחת שידורים
ב-Android יש שתי דרכים לאפליקציות לשלוח שידורים:
- השיטה
sendOrderedBroadcast(Intent, String)
שולחת שידורים למקלט אחד בכל פעם. כשכל מקלט מופעל בתורו, הוא יכול להעביר את התוצאה למקלט הבא. הוא יכול גם לבטל את השידור לגמרי כדי שהוא לא יגיע למקלטים אחרים. אתם יכולים לקבוע את הסדר שבו מקלטים יפעלו באותו תהליך של האפליקציה. כדי לעשות זאת, משתמשים במאפייןandroid:priority
של מסנן ה-Intent התואם. מקלטים עם אותה עדיפות מופעלים בסדר שרירותי. - השיטה
sendBroadcast(Intent)
שולחת שידורים לכל הנמענים בסדר לא מוגדר. הפעולה הזו נקראת שידור רגיל. היתרון של השיטה הזו הוא שהיא יעילה יותר, אבל החיסרון הוא שהמקבלים לא יכולים לקרוא תוצאות ממכשירים אחרים, להפיץ נתונים שהתקבלו מהשידור או לבטל את השידור.
קטע הקוד הבא מדגים איך לשלוח שידור באמצעות יצירת Intent וקריאה ל-sendBroadcast(Intent)
.
Kotlin
val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
putExtra("com.example.snippets.DATA", newData)
setPackage("com.example.snippets")
}
context.sendBroadcast(intent)
Java
Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);
הודעת השידור מוחצת באובייקט Intent
. המחרוזת action
של ה-intent חייבת לספק את התחביר של שם החבילה של האפליקציה ב-Java, ולזהות באופן ייחודי את אירוע השידור. אפשר לצרף מידע נוסף לכוונה באמצעות putExtra(String, Bundle)
. אפשר גם להגביל את השידור לקבוצה של אפליקציות באותו ארגון על ידי קריאה ל-setPackage(String)
ב-intent.
הגבלת שידורים באמצעות הרשאות
ההרשאות מאפשרות להגביל את השידור לקבוצת האפליקציות שיש להן הרשאות מסוימות. אתם יכולים לאכוף הגבלות על השולח או על הנמען של השידור.
שליחת שידורים עם הרשאות
כשקוראים ל-sendBroadcast(Intent, String)
או ל-sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle)
, אפשר לציין פרמטר הרשאה. רק מכשירים שביקשו את ההרשאה הזו באמצעות התג <uses-permission>
במניפסט שלהם יכולים לקבל את השידור. אם ההרשאה מסוכנת, צריך להעניק אותה כדי שהמקלט יוכל לקבל את השידור. לדוגמה, הקוד הבא שולח שידור עם הרשאה:
Kotlin
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)
Java
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);
כדי לקבל את השידור, האפליקציה המקבלת צריכה לבקש את ההרשאה באופן הבא:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
אפשר לציין הרשאת מערכת קיימת כמו BLUETOOTH_CONNECT
או להגדיר הרשאה מותאמת אישית באמצעות הרכיב <permission>
. למידע על הרשאות ואבטחה באופן כללי, עיינו במאמר הרשאות מערכת.
קבלת שידורים עם הרשאות
אם מציינים פרמטר הרשאה כשרושמים מקלט שידור (באמצעות registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
או בתג <receiver>
במניפסט), רק גורמים שמפיצים תוכן וביקשו את ההרשאה באמצעות התג <uses-permission>
במניפסט שלהם יכולים לשלוח כוונה (Intent) למקלט. אם ההרשאה מסוכנת, גם למפיץ צריכה להיות הרשאה.
לדוגמה, נניח שלאפליקציה המקבלת יש מקלט שמוצהר במניפסט באופן הבא:
<!-- If this receiver listens for broadcasts sent from the system or from
other apps, even other apps that you own, set android:exported to "true". -->
<receiver
android:name=".MyBroadcastReceiverWithPermission"
android:permission="android.permission.ACCESS_COARSE_LOCATION"
android:exported="true">
<intent-filter>
<action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
</intent-filter>
</receiver>
לחלופין, באפליקציה המקבלת יש מקלט עם רישום לפי הקשר באופן הבא:
Kotlin
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
)
Java
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
);
לאחר מכן, כדי שאפשר יהיה לשלוח שידורים לנמענים האלה, אפליקציית השליחה צריכה לבקש את ההרשאה באופן הבא:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
שיקולי אבטחה
ריכזנו כאן כמה שיקולים בנושא אבטחה לשליחה ולקבלה של שידורים:
אם הרבה אפליקציות נרשמו לקבלת אותה שידור ב-manifest שלהן, המערכת עשויה להפעיל הרבה אפליקציות, וכתוצאה מכך תהיה השפעה משמעותית על ביצועי המכשיר ועל חוויית המשתמש. כדי למנוע זאת, מומלץ להשתמש ברישום הקשר במקום בהצהרה על מניפסט. לפעמים, מערכת Android עצמה אוכפת את השימוש במקלטים שנרשמו לפי הקשר. לדוגמה, השידור
CONNECTIVITY_ACTION
מועבר רק לנמענים שרשומים לפי הקשר.אין לשדר מידע רגיש באמצעות כוונה משתמעת. כל אפליקציה יכולה לקרוא את המידע אם היא נרשמת לקבלת השידור. יש שלוש דרכים לקבוע מי יוכל לצפות בשידורים שלכם:
- אתם יכולים לציין הרשאה כשאתם שולחים שידור חי.
- ב-Android 4.0 (רמת API 14) ואילך, אפשר לציין חבילת נתונים באמצעות
setPackage(String)
כששולחים שידור. המערכת מגבילה את השידור לקבוצת האפליקציות שתואמות לחבילה.
כשמגדירים מקלט, כל אפליקציה יכולה לשלוח שידור שעלול להיות זדוני למקלט של האפליקציה. יש כמה דרכים להגביל את השידור שהאפליקציה מקבלת:
- אפשר לציין הרשאה כשרושמים מקלט שידור.
- במקרה של רכיבי קבלה (receiver) שמוגדרים במניפסט, אפשר להגדיר את המאפיין android:exported לערך 'false' במניפסט. המכשיר לא מקבל שידורים ממקורות מחוץ לאפליקציה.
מרחב השמות של פעולות השידור הוא גלובלי. חשוב לוודא ששמות הפעולות ומחרוזות אחרות נכתבים במרחב שמות שבבעלותכם. אחרת, יכול להיות שתיווצר לכם התנגשות לא מכוונת עם אפליקציות אחרות.
מכיוון ששיטת
onReceive(Context, Intent)
של מקלט פועלת בשרשור הראשי, היא אמורה לפעול ולחזור במהירות. אם אתם צריכים לבצע עבודה ממושכת, חשוב להיזהר מיצירת חוטים או הפעלת שירותי רקע, כי המערכת יכולה להרוג את התהליך כולו אחרי שהחזרה שלonReceive()
. למידע נוסף, ראו השפעה על מצב התהליך. כדי לבצע משימות ממושכות, מומלץ:- קריאה ל-
goAsync()
בשיטהonReceive()
של המכשיר המקבל והעברתBroadcastReceiver.PendingResult
לשרשור ברקע. כך השידור יישאר פעיל אחרי החזרה מ-onReceive()
. עם זאת, גם בגישה הזו המערכת מצפה שתסיימו את השידור מהר מאוד (תוך פחות מ-10 שניות). עם זאת, הוא מאפשר להעביר עבודה ל-thread אחר כדי למנוע תקלה ב-thread הראשי. - תזמון משימה באמצעות
JobScheduler
. למידע נוסף, קראו את המאמר תזמון משימות חכם.
- קריאה ל-
אל תתחילו פעילויות ממקלטי שידור, כי חוויית המשתמש תהיה מטרידה, במיוחד אם יש יותר ממקלט אחד. במקום זאת, מומלץ להציג הודעה.