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

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

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

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

เกี่ยวกับประกาศของระบบ

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

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

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

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

ดูรายการการดำเนินการออกอากาศของระบบทั้งหมดได้ที่BROADCAST_ACTIONS.TXTไฟล์ใน Android SDK การดําเนินการออกอากาศแต่ละรายการจะมีช่องคงที่ที่เชื่อมโยงอยู่ เช่น ค่าของค่าคงที่ ACTION_AIRPLANE_MODE_CHANGED คือ android.intent.action.AIRPLANE_MODE เอกสารประกอบสําหรับการดําเนินการออกอากาศแต่ละรายการมีอยู่ในช่องค่าคงที่ที่เกี่ยวข้อง

การเปลี่ยนแปลงการออกอากาศของระบบ

เมื่อแพลตฟอร์ม Android พัฒนาขึ้น ระบบจะเปลี่ยนลักษณะการออกอากาศเป็นระยะๆ โปรดคำนึงถึงการเปลี่ยนแปลงต่อไปนี้เพื่อรองรับ Android ทุกเวอร์ชัน

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.15.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.0.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-alpha02"
    }

    Kotlin

    dependencies {
        val core_version = "1.15.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.0.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-alpha02")
    }
  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. เลือกว่าควรส่งออกตัวรับสัญญาณการออกอากาศและแสดงให้แอปอื่นๆ ในอุปกรณ์เห็นหรือไม่ หากตัวรับนี้กำลังรับฟังการออกอากาศที่ส่งจากระบบหรือจากแอปอื่นๆ รวมถึงแอปอื่นๆ ที่คุณเป็นเจ้าของ ให้ใช้ Flag RECEIVER_EXPORTED หากตัวรับนี้คอยฟังเฉพาะการออกอากาศที่ส่งโดยแอปของคุณ ให้ใช้ Flag 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 เสมอ

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

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

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

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

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

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

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

ดังนั้น ตัวรับการออกอากาศไม่ควรเริ่มต้นเธรดเบื้องหลังที่ทำงานเป็นเวลานาน ระบบสามารถหยุดกระบวนการได้ทุกเมื่อหลังจาก onReceive() เพื่อเรียกคืนหน่วยความจำและสิ้นสุดเธรดที่สร้างขึ้น หากต้องการให้กระบวนการทำงานต่อไป ให้กำหนดเวลาJobService จากเครื่องรับโดยใช้ JobScheduler เพื่อให้ระบบทราบว่ากระบวนการยังคงทำงานอยู่ ภาพรวมของงานที่ทำอยู่เบื้องหลังมีรายละเอียดเพิ่มเติม

ส่งประกาศ

Android มี 2 วิธีที่แอปใช้ส่งการออกอากาศได้ ดังนี้

  • วิธีการ 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> ในไฟล์ 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> โปรดดูข้อมูลเกี่ยวกับสิทธิ์และความปลอดภัยโดยทั่วไปที่หัวข้อสิทธิ์ของระบบ

รับการออกอากาศที่มีสิทธิ์

หากคุณระบุพารามิเตอร์สิทธิ์เมื่อลงทะเบียนตัวรับการออกอากาศ (ไม่ว่าจะใช้แท็ก 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>

หรือแอปที่รับของคุณมี 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) ขึ้นไป คุณสามารถระบุ package ด้วย setPackage(String) เมื่อส่งการออกอากาศ ระบบจะจำกัดการออกอากาศไว้ที่ชุดแอปที่ตรงกับแพ็กเกจ
  • เมื่อคุณลงทะเบียนตัวรับ แอปใดก็ได้ที่จะส่งการออกอากาศที่อาจเป็นอันตรายไปยังตัวรับของแอปคุณ การจํากัดการออกอากาศที่แอปของคุณได้รับทำได้หลายวิธีดังนี้

    • คุณสามารถระบุสิทธิ์เมื่อลงทะเบียนตัวรับการออกอากาศ
    • สําหรับตัวรับที่ประกาศในไฟล์ Manifest คุณสามารถตั้งค่าแอตทริบิวต์ android:exported เป็น "false" ในไฟล์ Manifest ได้ ผู้รับจะไม่ได้รับการออกอากาศจากแหล่งที่มาภายนอกแอป
  • เนมสเปซสําหรับการดําเนินการแบบออกอากาศเป็นแบบส่วนกลาง ตรวจสอบว่าชื่อการดำเนินการและสตริงอื่นๆ เขียนในเนมสเปซที่คุณเป็นเจ้าของ ไม่เช่นนั้นคุณอาจแย่งสิทธิ์กับแอปอื่นๆ โดยไม่ได้ตั้งใจ

  • เนื่องจากเมธอด onReceive(Context, Intent) ของผู้รับทำงานบนเธรดหลัก จึงควรดำเนินการและแสดงผลได้อย่างรวดเร็ว หากต้องทํางานที่ทํางานเป็นเวลานาน โปรดระมัดระวังเกี่ยวกับการสร้างเธรดหรือเริ่มบริการที่ทำงานอยู่เบื้องหลัง เนื่องจากระบบอาจหยุดทั้งกระบวนการหลังจาก onReceive() แสดงผล ดูข้อมูลเพิ่มเติมได้ในผลต่อสถานะกระบวนการ หากต้องการทำงานที่ใช้เวลานาน เราขอแนะนําให้ทําดังนี้

    • การเรียก goAsync() ในเมธอด onReceive() ของผู้รับ และส่ง BroadcastReceiver.PendingResult ไปยังเธรดเบื้องหลัง ซึ่งจะทำให้การออกอากาศทำงานต่อไปได้หลังจากกลับมาจากonReceive() อย่างไรก็ตาม แม้จะใช้วิธีนี้ ระบบก็คาดหวังให้คุณออกอากาศให้เสร็จสิ้นอย่างรวดเร็ว (ภายใน 10 วินาที) แต่คุณสามารถย้ายงานไปยังชุดข้อความอื่นได้เพื่อหลีกเลี่ยงข้อบกพร่องของชุดข้อความหลัก
    • การกำหนดเวลางานด้วย JobScheduler ดูข้อมูลเพิ่มเติมได้ที่การกำหนดเวลางานอัจฉริยะ
  • อย่าเริ่มกิจกรรมจากตัวรับการออกอากาศเนื่องจากประสบการณ์ของผู้ใช้จะแย่ลง โดยเฉพาะอย่างยิ่งหากมีตัวรับมากกว่า 1 ตัว แต่ให้พิจารณาแสดงการแจ้งเตือนแทน