แอป Android จะส่งและรับข้อความประกาศจากระบบ Android และ แอป Android อื่นๆ ซึ่งคล้ายกับรูปแบบการออกแบบการเผยแพร่-ติดตาม โดยปกติแล้วระบบและแอปจะส่งประกาศเมื่อเกิดเหตุการณ์บางอย่าง ตัวอย่างเช่น ระบบ Android จะส่งประกาศเมื่อเกิดเหตุการณ์ต่างๆ ของระบบ เช่น การบูตระบบหรือการชาร์จอุปกรณ์ นอกจากนี้ แอปยังส่งประกาศที่กำหนดเองด้วย เช่น เพื่อแจ้งให้แอปอื่นๆ ทราบถึงสิ่งที่อาจเป็นที่สนใจ (เช่น การดาวน์โหลดข้อมูลใหม่)
แอปสามารถลงทะเบียนเพื่อรับประกาศที่เฉพาะเจาะจงได้ เมื่อมีการส่งประกาศ ระบบจะกำหนดเส้นทางประกาศไปยังแอปที่สมัครรับข้อมูลเพื่อรับประกาศประเภทนั้นโดยอัตโนมัติ
โดยทั่วไปแล้ว คุณสามารถใช้ประกาศเป็นระบบการรับส่งข้อความในแอปและนอกโฟลว์ผู้ใช้ปกติได้ อย่างไรก็ตาม คุณต้องระมัดระวังไม่ให้ใช้โอกาสในการตอบสนองต่อประกาศและเรียกใช้งานในเบื้องหลังในทางที่ผิด ซึ่งอาจทำให้ประสิทธิภาพของระบบช้าลง
เกี่ยวกับการประกาศของระบบ
ระบบจะส่งประกาศโดยอัตโนมัติเมื่อเกิดเหตุการณ์ต่างๆ ของระบบ เช่น เมื่อระบบเปลี่ยนเข้าและออกจากโหมดเครื่องบิน แอปที่สมัครรับข้อมูลทั้งหมดจะได้รับประกาศเหล่านี้
ออบเจ็กต์ Intent จะห่อหุ้มข้อความประกาศ สตริง action จะระบุ
เหตุการณ์ที่เกิดขึ้น เช่น android.intent.action.AIRPLANE_MODE นอกจากนี้ Intent อาจมีข้อมูลเพิ่มเติมที่รวมอยู่ในช่อง Extra
ตัวอย่างเช่น Intent ของโหมดเครื่องบินมี Extra แบบบูลีนที่ระบุว่าโหมดเครื่องบินเปิดอยู่หรือไม่
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีอ่าน Intent และรับสตริงการดำเนินการจาก an Intent ได้ที่ Intent และ Intent Filter
การดำเนินการประกาศของระบบ
ดูรายการการดำเนินการประกาศของระบบทั้งหมดได้ในไฟล์ 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 ขณะที่แอปอยู่ในสถานะแคช
เมื่อแอปเปลี่ยนจากสถานะแคชไปเป็นวงจรการทำงานของกระบวนการที่ ใช้งานอยู่,
ระบบจะส่งประกาศที่เลื่อนไว้
ประกาศที่สำคัญซึ่งประกาศไว้ในไฟล์ Manifest จะนำแอปออกจากสถานะแคชชั่วคราว เพื่อส่งประกาศ
Android 9
เริ่มตั้งแต่ Android 9 (ระดับ API 28) เป็นต้นไป การNETWORK_STATE_CHANGED_ACTION ประกาศจะไม่ได้รับข้อมูลเกี่ยวกับตำแหน่งของผู้ใช้หรือข้อมูลที่ระบุตัวบุคคลได้
หากแอปของคุณติดตั้งอยู่ในอุปกรณ์ที่ใช้ Android 9.0 (ระดับ API 28) ขึ้นไป ระบบจะไม่รวม SSID, BSSID, ข้อมูลการเชื่อมต่อ หรือผลการสแกนในการประกาศ Wi-Fi หากต้องการรับข้อมูลนี้ ให้เรียกใช้
getConnectionInfo() แทน
Android 8.0
เริ่มตั้งแต่ Android 8.0 (ระดับ API 26) เป็นต้นไป ระบบจะกำหนดข้อจำกัดเพิ่มเติมกับตัวรับสัญญาณที่ประกาศไว้ในไฟล์ Manifest
หากแอปกำหนดเป้าหมายเป็น Android 8.0 ขึ้นไป คุณจะใช้ไฟล์ Manifest เพื่อ ประกาศตัวรับสัญญาณสำหรับการประกาศ _โดยนัย_ ส่วนใหญ่ไม่ได้ (การประกาศที่ไม่ได้กำหนดเป้าหมายเป็น แอปของคุณโดยเฉพาะ) แต่คุณยังคงใช้ตัวรับสัญญาณที่ลงทะเบียนตามบริบท ได้เมื่อผู้ใช้ใช้แอปของคุณอยู่
Android 7.0
Android 7.0 (ระดับ API 24) ขึ้นไปจะไม่ส่งประกาศของระบบต่อไปนี้
นอกจากนี้ แอปที่กำหนดเป้าหมายเป็น Android 7.0 ขึ้นไปต้องลงทะเบียนการประกาศ
CONNECTIVITY_ACTION โดยใช้
registerReceiver(BroadcastReceiver, IntentFilter) การประกาศตัวรับสัญญาณในไฟล์ Manifest จะใช้ไม่ได้
รับประกาศ
แอปสามารถรับประกาศได้ 2 วิธี ได้แก่ ผ่านตัวรับสัญญาณที่ลงทะเบียนตามบริบทและตัวรับสัญญาณที่ประกาศไว้ในไฟล์ Manifest
ตัวรับสัญญาณที่ลงทะเบียนตามบริบท
ตัวรับสัญญาณที่ลงทะเบียนตามบริบทจะรับประกาศได้ตราบใดที่บริบทการลงทะเบียนยังคงใช้ได้ ซึ่งโดยปกติแล้วจะอยู่ระหว่างการเรียกใช้ registerReceiver และ
unregisterReceiver นอกจากนี้ บริบทการลงทะเบียนจะใช้ไม่ได้เมื่อระบบทำลายบริบทที่เกี่ยวข้อง ตัวอย่างเช่น หากคุณลงทะเบียนภายใน
บริบท Activity คุณจะได้รับประกาศตราบใดที่กิจกรรม
ยังคงใช้งานอยู่ หากคุณลงทะเบียนด้วยบริบทแอปพลิเคชัน คุณจะได้รับประกาศตราบใดที่แอปทำงานอยู่
หากต้องการลงทะเบียนตัวรับสัญญาณด้วยบริบท ให้ทำตามขั้นตอนต่อไปนี้
ในไฟล์ Build ระดับโมดูลของแอป ให้รวมไลบรารี AndroidX Core เวอร์ชัน 1.9.0 ขึ้นไป:
Groovy
dependencies { def core_version = "1.18.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" }
Kotlin
dependencies { val core_version = "1.18.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") }
สร้างอินสแตนซ์ของ
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");เลือกว่าควรส่งออกและแสดง Broadcast Receiver ให้แอปอื่นๆ ในอุปกรณ์เห็นหรือไม่ หากตัวรับสัญญาณนี้กำลังรอรับประกาศที่ส่งจากระบบหรือจากแอปอื่นๆ แม้แต่แอปอื่นๆ ที่คุณเป็นเจ้าของ ให้ใช้แฟล็ก
RECEIVER_EXPORTEDแต่หากตัวรับสัญญาณนี้กำลังรอรับเฉพาะประกาศที่ส่งโดยแอปของคุณ ให้ใช้แฟล็กRECEIVER_NOT_EXPORTEDKotlin
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)อย่าลืมยกเลิกการลงทะเบียนตัวรับสัญญาณเมื่อไม่ต้องการใช้อีกต่อไปหรือบริบทใช้ไม่ได้อีกต่อไป
ยกเลิกการลงทะเบียน Broadcast Receiver ของคุณ
ขณะที่ Broadcast Receiver ลงทะเบียนอยู่ Broadcast Receiver จะเก็บข้อมูลอ้างอิงถึงบริบทที่คุณลงทะเบียนไว้ ซึ่งอาจทำให้เกิดการรั่วไหลหากขอบเขตที่ลงทะเบียนของตัวรับสัญญาณเกินขอบเขตวงจรการทำงานของบริบท ตัวอย่างเช่น ปัญหานี้อาจเกิดขึ้นเมื่อคุณลงทะเบียนตัวรับสัญญาณในขอบเขตกิจกรรม แต่ลืมยกเลิกการลงทะเบียนเมื่อระบบทำลายกิจกรรม ดังนั้น ให้ยกเลิกการลงทะเบียน Broadcast Receiver ของคุณเสมอ
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
}
}
ลงทะเบียนตัวรับสัญญาณในขอบเขตที่เล็กที่สุด
คุณควรลงทะเบียน Broadcast Receiver เมื่อสนใจผลลัพธ์จริงๆ เท่านั้น เลือกขอบเขตตัวรับสัญญาณที่เล็กที่สุดเท่าที่จะเป็นไปได้
LifecycleResumeEffectหรือเมธอดวงจรกิจกรรมonResume/onPauseของกิจกรรม: Broadcast Receiver จะได้รับการอัปเดตเฉพาะขณะที่แอปอยู่ในสถานะกลับมาทำงานต่อLifecycleStartEffectหรือเมธอดวงจรกิจกรรมonStart/onStopของกิจกรรม: Broadcast Receiver จะได้รับการอัปเดตเฉพาะขณะที่แอปอยู่ในสถานะกลับมาทำงานต่อDisposableEffect: Broadcast Receiver จะได้รับการอัปเดตเฉพาะขณะที่ Composable ได้อยู่ในแผนผังการคอมโพส ขอบเขตนี้ไม่ได้แนบอยู่กับขอบเขตวงจรกิจกรรม ลองลงทะเบียนตัวรับสัญญาณในบริบทแอปพลิเคชัน เนื่องจากในทางทฤษฎีแล้ว คอมโพสได้อาจมีอายุการใช้งานยาวนานกว่าขอบเขตวงจรกิจกรรมและทำให้เกิดการรั่วไหลของกิจกรรมonCreate/onDestroyของกิจกรรม: Broadcast Receiver จะได้รับการอัปเดตขณะที่กิจกรรมอยู่ในสถานะสร้าง อย่าลืมยกเลิกการลงทะเบียนในonDestroy()ไม่ใช่onSaveInstanceState(Bundle)เนื่องจากระบบอาจไม่เรียกใช้เมธอดนี้- ขอบเขตที่กำหนดเอง: ตัวอย่างเช่น คุณสามารถลงทะเบียนตัวรับสัญญาณในขอบเขต
ViewModelเพื่อให้ตัวรับสัญญาณยังคงอยู่ได้แม้จะมีการสร้างกิจกรรมขึ้นใหม่ อย่าลืมใช้บริบทแอปพลิเคชันเพื่อลงทะเบียนตัวรับสัญญาณ เนื่องจากตัวรับสัญญาณอาจมีอายุการใช้งานยาวนานกว่าขอบเขตวงจรการทำงานของกิจกรรมและทำให้เกิดการรั่วไหลของกิจกรรม
สร้างคอมโพสได้แบบมีสถานะและไม่มีสถานะ
Compose มี Composable แบบมีสถานะและไม่มีสถานะ การลงทะเบียนหรือยกเลิกการลงทะเบียน Broadcast Receiver ภายใน Composable จะทำให้ Composable มีสถานะ คอมโพสได้ไม่ใช่ฟังก์ชันที่กำหนดได้ซึ่งแสดงผลเนื้อหาเดียวกันเมื่อส่งพารามิเตอร์เดียวกัน สถานะภายในอาจเปลี่ยนแปลงได้ตามการเรียกใช้ตัวรับสัญญาณประกาศที่ลงทะเบียนไว้
แนวทางปฏิบัติแนะนำใน Compose คือการแยก Composable ออกเป็นเวอร์ชันแบบมีสถานะและไม่มีสถานะ ดังนั้น เราขอแนะนำให้คุณยกการสร้าง Broadcast Receiver ออกจาก Composable เพื่อให้ Broadcast Receiver ไม่มีสถานะ
@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
}
ตัวรับสัญญาณที่ประกาศไว้ในไฟล์ Manifest
หากคุณประกาศ Broadcast Receiver ในไฟล์ Manifest ระบบจะเปิดแอปเมื่อมีการส่งประกาศ หากแอปยังไม่ได้ทำงาน ระบบจะเปิดแอป
การประกาศโดยนัยคือการประกาศที่ไม่ได้กำหนดเป้าหมายเป็นแอปของคุณโดยเฉพาะ ในกรณีส่วนใหญ่ คุณสามารถ ใช้ การเรียกใช้งานตามกำหนดเวลา แทนได้หากต้องการประกาศ Broadcast Receiver ในไฟล์ Manifest ให้ทำตามขั้นตอนต่อไปนี้
ระบุองค์ประกอบ
<receiver>ในไฟล์ Manifest ของแอป<!-- 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 Filter จะระบุการดำเนินการประกาศที่ตัวรับสัญญาณสมัครรับข้อมูล
สร้างคลาสย่อย
BroadcastReceiverและใช้onReceive(Context, Intent)Broadcast Receiver ในตัวอย่างต่อไปนี้จะบันทึกและแสดงเนื้อหาของประกาศ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()
ความสำคัญของกระบวนการโฮสต์ของตัวรับสัญญาณจะขึ้นอยู่กับคอมโพเนนต์ของแอป หากกระบวนการนั้นโฮสต์เฉพาะตัวรับสัญญาณที่ประกาศไว้ในไฟล์ Manifest ระบบอาจหยุดกระบวนการหลังจาก onReceive() เพื่อเพิ่มทรัพยากรให้กับกระบวนการอื่นๆ ที่สำคัญกว่า ซึ่งมักเกิดขึ้นกับแอปที่ผู้ใช้ไม่เคยโต้ตอบด้วยหรือไม่ได้โต้ตอบด้วยเมื่อเร็วๆ นี้
ดังนั้น ตัวรับสัญญาณประกาศจึงไม่ควรเริ่มเทรดเบื้องหลังที่ทำงานเป็นเวลานาน
ระบบสามารถหยุดกระบวนการได้ทุกเมื่อหลังจาก onReceive() เพื่อเรียกคืนหน่วยความจำ ซึ่งจะยุติเทรดที่สร้างขึ้น หากต้องการให้กระบวนการทำงานอยู่ ให้กำหนดเวลา
JobService จากตัวรับสัญญาณโดยใช้ JobScheduler เพื่อให้ระบบทราบว่ากระบวนการยังคงทำงานอยู่ ภาพรวมของงานเบื้องหลัง
ดูรายละเอียดเพิ่มเติมได้ที่
ส่งประกาศ
Android มี 2 วิธีให้แอปส่งประกาศ
- เมธอด
sendOrderedBroadcast(Intent, String)จะส่งประกาศไปยัง ตัวรับสัญญาณทีละรายการ เมื่อตัวรับสัญญาณแต่ละรายการทำงานตามลำดับ ตัวรับสัญญาณจะส่งต่อผลลัพธ์ไปยังตัวรับสัญญาณถัดไปได้ นอกจากนี้ ตัวรับสัญญาณยังยกเลิกประกาศโดยสมบูรณ์ได้ เพื่อไม่ให้ประกาศไปถึงตัวรับสัญญาณอื่นๆ คุณสามารถควบคุมลำดับที่ตัวรับสัญญาณทำงานภายในกระบวนการของแอปเดียวกันได้ โดยใช้แอตทริบิวต์android:priorityของ Intent Filter ที่ตรงกัน ตัวรับสัญญาณที่มีลำดับความสำคัญเดียวกันจะทำงานตามลำดับที่กำหนด - เมธอด
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 ของแอปและระบุเหตุการณ์ประกาศที่ไม่ซ้ำกัน คุณสามารถแนบข้อมูลเพิ่มเติมกับ
Intent ได้ด้วย putExtra(String, Bundle) นอกจากนี้ คุณยังจำกัดการประกาศให้เฉพาะ
แอปบางแอปในองค์กรเดียวกันได้โดยเรียกใช้ setPackage(String) ใน
Intent
จำกัดการประกาศด้วยสิทธิ์
สิทธิ์ช่วยให้คุณจำกัดการประกาศให้เฉพาะแอปบางแอปที่มีสิทธิ์บางอย่าง คุณสามารถบังคับใช้ข้อจำกัดกับผู้ส่งหรือผู้รับประกาศก็ได้
ส่งประกาศด้วยสิทธิ์
เมื่อเรียกใช้ sendBroadcast(Intent, String) หรือ
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle)
คุณสามารถระบุพารามิเตอร์สิทธิ์ได้ เฉพาะตัวรับสัญญาณที่ขอสิทธิ์ดังกล่าวด้วยแท็ก <uses-permission> ในไฟล์ Manifest เท่านั้นที่จะรับประกาศได้ หากสิทธิ์เป็นสิทธิ์ที่เป็นอันตราย คุณต้องให้สิทธิ์ก่อนตัวรับสัญญาณจึงจะรับประกาศได้ ตัวอย่างเช่น โค้ดต่อไปนี้จะส่งประกาศพร้อมสิทธิ์
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> ดูข้อมูลเกี่ยวกับสิทธิ์และความปลอดภัยโดยทั่วไปได้ที่
สิทธิ์ของระบบ
รับประกาศด้วยสิทธิ์
หากคุณระบุพารามิเตอร์สิทธิ์เมื่อลงทะเบียน Broadcast Receiver (ด้วย registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) หรือใน <receiver> แท็กในไฟล์ Manifest) เฉพาะผู้ประกาศที่ขอสิทธิ์ด้วยแท็ก <uses-permission> ในไฟล์ Manifest เท่านั้นที่จะส่ง Intent ไปยัง Broadcast Receiver ได้ หากสิทธิ์เป็นสิทธิ์ที่เป็นอันตราย ผู้ประกาศต้องได้รับสิทธิ์ด้วย
ตัวอย่างเช่น สมมติว่าแอปที่รับมีตัวรับสัญญาณที่ประกาศไว้ในไฟล์ Manifest ดังนี้
<!-- 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 อาจทำให้ระบบเปิดแอปจำนวนมาก ซึ่งส่งผลกระทบอย่างมากต่อทั้งประสิทธิภาพของอุปกรณ์และประสบการณ์ของผู้ใช้ หากต้องการหลีกเลี่ยงปัญหานี้ ให้ใช้การลงทะเบียนตามบริบทแทนการประกาศในไฟล์ Manifest บางครั้งระบบ Android เองก็บังคับให้ใช้ตัวรับสัญญาณที่ลงทะเบียนตามบริบท ตัวอย่างเช่น ระบบจะส่งประกาศ
CONNECTIVITY_ACTIONไปยัง ตัวรับสัญญาณที่ลงทะเบียนตามบริบทเท่านั้นอย่าประกาศข้อมูลที่ละเอียดอ่อนโดยใช้ Intent แบบไม่เจาะจงปลายทาง แอปใดๆ ก็อ่านข้อมูลได้หากลงทะเบียนเพื่อรับประกาศ คุณควบคุมผู้ที่รับประกาศได้ 3 วิธีดังนี้
- คุณสามารถระบุสิทธิ์เมื่อส่งประกาศ
- ใน Android 4.0 (ระดับ API 14) ขึ้นไป คุณสามารถระบุa
แพ็กเกจ ด้วย
setPackage(String)เมื่อส่งประกาศ ระบบจะจำกัดการประกาศให้เฉพาะแอปบางแอปที่ตรงกับแพ็กเกจ
เมื่อคุณลงทะเบียนตัวรับสัญญาณ แอปใดๆ ก็ส่งประกาศที่อาจเป็นอันตรายไปยังตัวรับสัญญาณของแอปคุณได้ คุณจำกัดประกาศที่แอปได้รับได้หลายวิธีดังนี้
- คุณสามารถระบุสิทธิ์เมื่อลงทะเบียน Broadcast Receiver
- สำหรับตัวรับสัญญาณที่ประกาศไว้ในไฟล์ Manifest คุณสามารถตั้งค่าแอตทริบิวต์ android:exported เป็น "false" ในไฟล์ Manifest ตัวรับสัญญาณจะไม่รับประกาศจากแหล่งที่มาภายนอกแอป
เนมสเปซสำหรับการดำเนินการประกาศเป็นแบบส่วนกลาง ตรวจสอบว่าชื่อการดำเนินการและสตริงอื่นๆ เขียนอยู่ในเนมสเปซที่คุณเป็นเจ้าของ มิฉะนั้น คุณอาจเกิดความขัดแย้งกับแอปอื่นๆ โดยไม่ตั้งใจ
เนื่องจากเมธอด
onReceive(Context, Intent)ของตัวรับสัญญาณทำงานในเทรดหลัก เมธอดจึงควรดำเนินการและกลับมาทำงานต่ออย่างรวดเร็ว หากคุณต้องทำงานที่ใช้เวลานาน ให้ระมัดระวังในการสร้างเทรดหรือเริ่มบริการเบื้องหลัง เนื่องจากระบบสามารถหยุดกระบวนการทั้งหมดได้หลังจากonReceive()กลับมาทำงานต่อ ดูข้อมูลเพิ่มเติมได้ที่ ผลกระทบต่อสถานะกระบวนการ หากต้องการทำงานที่ใช้เวลานาน เราขอแนะนำให้ทำดังนี้- เรียกใช้
goAsync()ในเมธอดonReceive()ของตัวรับสัญญาณและ ส่งBroadcastReceiver.PendingResultไปยังเทรดเบื้องหลัง การดำเนินการนี้จะทำให้ประกาศยังคงใช้งานอยู่หลังจากกลับมาจากonReceive()อย่างไรก็ตาม แม้จะใช้วิธีนี้ ระบบก็คาดหวังให้คุณดำเนินการกับประกาศให้เสร็จอย่างรวดเร็ว (ภายใน 10 วินาที) แต่ระบบอนุญาตให้คุณย้ายงานไปยังเทรดอื่นเพื่อหลีกเลี่ยงไม่ให้เทรดหลักเกิดข้อผิดพลาด - กำหนดเวลาการเรียกใช้งานด้วย
JobSchedulerดูข้อมูลเพิ่มเติมได้ที่ ดู การกำหนดเวลาการเรียกใช้งานอัจฉริยะ
- เรียกใช้
อย่าเริ่มกิจกรรมจากตัวรับสัญญาณประกาศ เนื่องจากประสบการณ์ของผู้ใช้จะสะดุด โดยเฉพาะอย่างยิ่งหากมีตัวรับสัญญาณมากกว่า 1 รายการ ให้พิจารณา แสดงการแจ้งเตือนแทน