ภาพรวมการออกอากาศ

แอป Android จะส่งและรับข้อความประกาศจากระบบ Android และแอป Android อื่นๆ ในลักษณะเดียวกับรูปแบบการออกแบบการเผยแพร่-สมัครรับข้อมูล โดยปกติแล้ว ระบบและแอปจะส่งการบรอดแคสต์เมื่อเกิดเหตุการณ์บางอย่าง ตัวอย่างเช่น ระบบ Android จะส่งการบรอดแคสต์เมื่อเกิดเหตุการณ์ต่างๆ ของระบบ เช่น การบูตระบบหรือการชาร์จอุปกรณ์ นอกจากนี้ แอปยังส่งการบรอดแคสต์ที่กำหนดเองด้วย เช่น เพื่อแจ้งให้แอปอื่นๆ ทราบถึงสิ่งที่อาจเป็นที่สนใจ (เช่น การดาวน์โหลดข้อมูลใหม่)

แอปสามารถลงทะเบียนเพื่อรับการบรอดแคสต์ที่เฉพาะเจาะจงได้ เมื่อมีการส่งการบรอดแคสต์ ระบบจะกำหนดเส้นทางการบรอดแคสต์ไปยังแอปที่สมัครรับข้อมูลเพื่อรับการบรอดแคสต์ประเภทนั้นโดยอัตโนมัติ

โดยทั่วไปแล้ว การบรอดแคสต์สามารถใช้เป็นระบบการรับส่งข้อความระหว่างแอปและภายนอกโฟลว์ผู้ใช้ปกติ อย่างไรก็ตาม คุณต้องระมัดระวังไม่ให้ใช้โอกาสในการตอบสนองต่อการบรอดแคสต์และเรียกใช้การทำงานในเบื้องหลังในทางที่ผิด ซึ่งอาจทำให้ประสิทธิภาพของระบบช้าลง

เกี่ยวกับการบรอดแคสต์ของระบบ

ระบบจะส่งการบรอดแคสต์โดยอัตโนมัติเมื่อเกิดเหตุการณ์ต่างๆ ของระบบ เช่น เมื่อระบบเปลี่ยนเข้าและออกจากโหมดบนเครื่องบิน แอปที่สมัครรับข้อมูลทั้งหมดจะได้รับการบรอดแคสต์เหล่านี้

ออบเจ็กต์ Intent จะห่อหุ้มข้อความประกาศ สตริง action จะระบุ เหตุการณ์ที่เกิดขึ้น เช่น android.intent.action.AIRPLANE_MODE นอกจากนี้ Intent ยังอาจมีข้อมูลเพิ่มเติมที่รวมอยู่ในฟิลด์ Extra ตัวอย่างเช่น Intent ของโหมดบนเครื่องบินมี Extra แบบบูลีนที่ระบุว่าโหมดบนเครื่องบินเปิดอยู่หรือไม่

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีอ่าน Intent และรับสตริงการดำเนินการจาก Intent ได้ที่ Intent และตัวกรอง Intent

การดำเนินการประกาศของระบบ

ดูรายการการดำเนินการบรอดแคสต์ของระบบทั้งหมดได้ที่ไฟล์ 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 คุณจะได้รับการบรอดแคสต์ตราบใดที่กิจกรรม ยังคงใช้งานอยู่ หากคุณลงทะเบียนด้วยบริบทแอปพลิเคชัน คุณจะได้รับการบรอดแคสต์ตราบใดที่แอปทำงานอยู่

หากต้องการลงทะเบียนตัวรับด้วยบริบท ให้ทำตามขั้นตอนต่อไปนี้

  1. ในไฟล์บิลด์ระดับโมดูลของแอป ให้รวมไลบรารี AndroidX Core เวอร์ชัน 1.9.0 ขึ้นไป:

    Groovy

    dependencies {
        def core_version = "1.19.1"
    
        // 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.19.1"
    
        // 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")
    }
  2. สร้างอินสแตนซ์ของ BroadcastReceiver:

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    Java

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. สร้างอินสแตนซ์ของ IntentFilter:

    Kotlin

    val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
    

    Java

    IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
    
  4. เลือกว่าจะส่งออก Broadcast Receiver และให้แอปอื่นๆ ในอุปกรณ์มองเห็นได้หรือไม่ หากตัวรับนี้กำลังรอรับการบรอดแคสต์ที่ส่งจากระบบหรือจากแอปอื่นๆ แม้แต่แอปอื่นๆ ที่คุณเป็นเจ้าของ ให้ใช้แฟล็ก 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;
    
  5. ลงทะเบียนตัวรับโดยเรียกใช้ registerReceiver()

    Kotlin

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
    

    Java

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. หากต้องการหยุดรับการบรอดแคสต์ ให้เรียกใช้ unregisterReceiver(android.content.BroadcastReceiver) อย่าลืมยกเลิกการลงทะเบียนตัวรับเมื่อไม่ต้องการตัวรับนั้นอีกต่อไปหรือบริบทไม่ถูกต้องอีกต่อไป

ยกเลิกการลงทะเบียน 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 อยู่ในแผนผัง Composition ขอบเขตนี้ไม่ได้แนบอยู่กับขอบเขตวงจรกิจกรรม พิจารณาลงทะเบียนตัวรับในบริบทแอปพลิเคชัน เนื่องจากในทางทฤษฎีแล้ว Composable อาจมีอายุการใช้งานยาวนานกว่าขอบเขตวงจรกิจกรรมและทำให้เกิดการรั่วไหลของกิจกรรม
  • onCreate/onDestroy ของกิจกรรม: Broadcast Receiver จะได้รับการอัปเดตขณะที่กิจกรรมอยู่ในสถานะสร้าง อย่าลืมยกเลิกการลงทะเบียนใน onDestroy() ไม่ใช่ onSaveInstanceState(Bundle) เนื่องจากระบบอาจไม่เรียกใช้เมธอดนี้
  • ขอบเขตที่กำหนดเอง: ตัวอย่างเช่น คุณสามารถลงทะเบียนตัวรับในขอบเขต ViewModel เพื่อให้ตัวรับยังคงอยู่ได้แม้จะมีการสร้างกิจกรรมขึ้นใหม่ อย่าลืมใช้บริบทแอปพลิเคชันเพื่อลงทะเบียนตัวรับ เนื่องจากตัวรับอาจมีอายุการใช้งานยาวนานกว่าขอบเขตวงจรการทำงานของกิจกรรมและทำให้เกิดการรั่วไหลของกิจกรรม

สร้างคอมโพสได้แบบมีสถานะและไม่มีสถานะ

Compose มี Composable แบบเก็บสถานะและไม่เก็บสถานะ การลงทะเบียนหรือยกเลิกการลงทะเบียน Broadcast Receiver ภายใน Composable จะทำให้ Composable นั้นเก็บสถานะ คอมโพสได้ไม่ใช่ฟังก์ชันที่กำหนดได้ซึ่งแสดงผลเนื้อหาเดียวกันเมื่อส่งพารามิเตอร์เดียวกัน สถานะภายในอาจเปลี่ยนแปลงตามการเรียกใช้ตัวรับการบรอดแคสต์ที่ลงทะเบียนไว้

แนวทางปฏิบัติแนะนำใน 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
}

ตัวรับที่ประกาศไว้ในไฟล์ Manifest

หากคุณประกาศ Broadcast Receiver ในไฟล์ Manifest ระบบจะเปิดแอปเมื่อมีการส่งการบรอดแคสต์ หากแอปยังไม่ได้ทำงาน ระบบจะเปิดแอป

หากต้องการประกาศ Broadcast Receiver ในไฟล์ Manifest ให้ทำตามขั้นตอนต่อไปนี้

  1. ระบุองค์ประกอบ <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 จะระบุการดำเนินการประกาศที่ตัวรับสมัครรับข้อมูล

  2. สร้างคลาสย่อย 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() เพื่อเพิ่มทรัพยากรให้กับกระบวนการอื่นๆ ที่สำคัญกว่า ซึ่งเป็นเรื่องปกติสำหรับแอปที่ผู้ใช้ไม่เคยโต้ตอบด้วยหรือไม่ได้โต้ตอบด้วยเมื่อเร็วๆ นี้

ดังนั้น Broadcast Receiver จึงไม่ควรเริ่มเทรดเบื้องหลังที่ทำงานเป็นเวลานาน ระบบสามารถหยุดกระบวนการได้ทุกเมื่อหลังจาก 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 ไปยังตัวรับได้ หากสิทธิ์เป็นสิทธิ์ที่เป็นอันตราย ผู้บรอดแคสต์ต้องได้รับสิทธิ์ด้วย

ตัวอย่างเช่น สมมติว่าแอปที่รับมีตัวรับที่ประกาศไว้ในไฟล์ 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" />

หลีกเลี่ยงการบรอดแคสต์ภายในกระบวนการเดียวกัน

การบรอดแคสต์ได้รับการออกแบบให้เป็นกลไกการสื่อสารระหว่างโปรเซส (IPC) สำหรับการส่งข้อความระหว่างแอปต่างๆ หรือระหว่างระบบกับแอป การส่ง การบรอดแคสต์ด้วยตนเอง ซึ่งเป็นการบรอดแคสต์ที่ตัวรับ ทั้งหมด ของ ตัวรับทำงานในกระบวนการเดียวกันกับที่ส่งการบรอดแคสต์นั้นไม่มีประสิทธิภาพอย่างมาก สร้างค่าใช้จ่ายที่ไม่จำเป็นของระบบ และไม่แนะนำอย่างยิ่ง

สถานการณ์ที่พบบ่อย 2 กรณีที่แอปส่งการบรอดแคสต์ไปยังตัวเอง ได้แก่

  • การสื่อสารระหว่างคอมโพเนนต์ในกระบวนการเดียวกัน: เช่น การส่งเหตุการณ์หรือข้อมูลระหว่างกิจกรรม, Fragment, บริการ หรือ เทรดเบื้องหลัง ให้ใช้กลไกการสื่อสารมาตรฐานในกระบวนการ เช่น รูปแบบ Observer หรือสตรีมแบบรีแอกทีฟ แทนการส่งการบรอดแคสต์

    • Kotlin Flow (SharedFlow และ StateFlow): โซลูชันที่ทันสมัย และเป็นสำนวนใน Kotlin สำหรับการปล่อยและสังเกตสตรีมเหตุการณ์ หรือการอัปเดตสถานะในคอร์รูทีนและคอมโพเนนต์ในแอป
    • ViewModel ที่แชร์: ช่วยให้แชร์ข้อมูลและเหตุการณ์ ระหว่างคอมโพเนนต์ UI ต่างๆ (เช่น Fragment หรือคอมโพสได้) ภายในกิจกรรมเดียวกัน
    • การเรียกกลับและ Listener: การเรียกกลับอินเทอร์เฟซมาตรฐานหรือข้อมูลอ้างอิงฟังก์ชัน ที่ส่งระหว่างคอมโพเนนต์โดยตรง หรือลงทะเบียนกับ ที่เก็บหรือคอนโทรลเลอร์ส่วนกลาง
  • การจัดการเหตุการณ์ของระบบ การทำงาน หรือการปลุก: เช่น การรับการทำงานที่กำหนดเวลาไว้ การปลุก หรือการเรียกกลับของระบบ แล้วส่งการบรอดแคสต์เพื่อทริกเกอร์การทำงานจริง ให้ทำงานให้เสร็จสมบูรณ์โดยตรงภายในงานนั้น (เช่น JobService หรือ Worker ของ WorkManager), ตัวแฮนเดิลการปลุก หรือคอมโพเนนต์การเรียกกลับของระบบ หรือมอบหมายงานไปยังคลาส<b>ตรรกะทางธุรกิจ</b>ของแอปโดยตรง แทนการส่งการบรอดแคสต์

ในอุปกรณ์ที่ใช้ Android 17 QPR2 ขึ้นไป ระบบจะ ส่งการบรอดแคสต์ด้วยตนเองอย่างมีประสิทธิภาพมากขึ้นโดยส่งการบรอดแคสต์กลับไปยัง กระบวนการที่ส่ง ซึ่งจะส่งการบรอดแคสต์ไปยังตัวรับของตนเองในเทรดหลัก การส่งการบรอดแคสต์ด้วยตนเองจะไม่เพิ่มความสำคัญของกระบวนการและจะไม่ป้องกันไม่ให้กระบวนการที่แคชไว้หยุดทำงาน ดังนั้นอย่าใช้การบรอดแคสต์ด้วยตนเองเพื่อให้แอปทำงานอยู่หรือทำงานในเบื้องหลัง แต่ให้เลือก API ที่เหมาะสมกับงานของคุณตามที่อธิบายไว้ใน ภาพรวมของงานเบื้องหลัง แม้จะมีการเพิ่มประสิทธิภาพนี้ การบรอดแคสต์ด้วยตนเองก็มีประสิทธิภาพน้อยกว่ากลไกการสื่อสารในกระบวนการ ดังนั้นให้ใช้ทางเลือกอื่นแทน

ดูข้อมูลเพิ่มเติมเกี่ยวกับการออกแบบการสื่อสารระหว่างคอมโพเนนต์ของแอปได้ที่ คู่มือสถาปัตยกรรมแอป

ข้อควรพิจารณาด้านความปลอดภัย

ข้อควรพิจารณาด้านความปลอดภัยบางประการสำหรับการส่งและรับการบรอดแคสต์มีดังนี้

  • หากแอปจำนวนมากลงทะเบียนเพื่อรับการบรอดแคสต์เดียวกันในไฟล์ 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 ดูข้อมูลเพิ่มเติมได้ที่ ดู การกำหนดเวลาการทำงานอย่างชาญฉลาด
  • อย่าเริ่มกิจกรรมจาก Broadcast Receiver เนื่องจากประสบการณ์ของผู้ใช้จะสะดุด โดยเฉพาะอย่างยิ่งหากมี Broadcast Receiver มากกว่า 1 ราย แต่ให้พิจารณา แสดงการแจ้งเตือนแทน