Ringkasan siaran

Aplikasi Android dapat mengirim atau menerima pesan siaran dari sistem Android dan aplikasi Android lainnya, mirip dengan publikasikan-langganan pola desain. Siaran ini dikirim saat peristiwa menarik terjadi. Misalnya, sistem Android mengirimkan siaran ketika berbagai peristiwa sistem terjadi, seperti saat sistem melakukan booting atau perangkat mulai mengisi daya. Aplikasi juga bisa mengirim siaran khusus, misalnya, untuk memberi tahu aplikasi lain tentang sesuatu yang mungkin mereka minati (misalnya, beberapa data baru memiliki yang didownload).

Sistem mengoptimalkan penyampaian siaran untuk mempertahankan kesehatan sistem yang optimal. Oleh karena itu, waktu pengiriman siaran tidak dijamin efektif. Aplikasi yang membutuhkan komunikasi antar-proses berlatensi rendah harus pertimbangkan layanan terikat.

Aplikasi dapat mendaftar untuk menerima siaran tertentu. Ketika {i>broadcast<i} dikirim, sistem secara otomatis merutekan siaran ke aplikasi yang telah berlangganan menerima jenis siaran tertentu tersebut.

Secara umum, siaran dapat digunakan sebagai sistem pesan di berbagai aplikasi dan di luar alur pengguna normal. Namun, Anda harus berhati-hati agar tidak menyalahgunakan kesempatan untuk merespons siaran dan menjalankan tugas di latar belakang yang dapat menyebabkan kinerja sistem yang lambat.

Tentang siaran sistem

Sistem secara otomatis mengirim {i>broadcast<i} ketika berbagai peristiwa sistem terjadi, seperti saat sistem beralih masuk dan keluar dari mode pesawat. {i>System<i}. siaran dikirim ke semua aplikasi yang berlangganan untuk menerima peristiwa.

Pesan siaran itu sendiri digabungkan dalam Intent objek yang string tindakannya mengidentifikasi peristiwa yang terjadi (misalnya android.intent.action.AIRPLANE_MODE). Niat juga dapat mencakup informasi tambahan yang dibundel ke dalam ruang isian ekstranya. Misalnya, pesawat terbang intent mode menyertakan tambahan boolean yang menunjukkan apakah Pesawat Mode aktif.

Untuk informasi selengkapnya tentang cara membaca intent dan mendapatkan string tindakan dari intent, lihat Intent dan Intent Filter.

Untuk daftar lengkap tindakan siaran sistem, lihat File BROADCAST_ACTIONS.TXT di Android SDK. Setiap tindakan siaran memiliki konstan yang terkait dengannya. Misalnya, nilai konstanta ACTION_AIRPLANE_MODE_CHANGED sama dengan android.intent.action.AIRPLANE_MODE. Dokumentasi untuk setiap tindakan siaran tersedia dalam bidang konstanta terkait.

Perubahan pada siaran sistem

Seiring berkembangnya platform Android, platform ini secara berkala mengubah cara siaran sistem berperilaku. Perhatikan perubahan berikut untuk mendukung semua versi Android.

Android 14

Saat aplikasi berada dalam di-cache status, pengiriman siaran ditetapkan yang dioptimalkan untuk kesehatan sistem. Misalnya, siaran sistem yang kurang penting seperti sebagai ACTION_SCREEN_ON adalah ditangguhkan saat aplikasi dalam keadaan {i>cache<i}. Setelah aplikasi keluar dari cache status menjadi proses aktif siklus proses, sistem akan memberikan setiap siaran yang ditangguhkan.

Siaran penting yang dideklarasikan dalam manifes akan menghapus aplikasi dari cache untuk sementara status pengiriman.

Android 9

Mulai Android 9 (API level 28), NETWORK_STATE_CHANGED_ACTION tidak menerima informasi tentang lokasi pengguna atau secara pribadi data yang dapat diidentifikasi.

Selain itu, jika aplikasi Anda diinstal pada perangkat yang menjalankan Android 9 atau yang lebih tinggi, siaran sistem dari Wi-Fi tidak berisi SSID, BSSID, atau koneksi informasi, atau memindai hasil. Untuk mendapatkan informasi ini, hubungi getConnectionInfo() sebagai gantinya.

Android 8.0

Mulai Android 8.0 (API level 26), sistem menerapkan pada penerima yang dideklarasikan manifes.

Jika aplikasi Anda menargetkan Android 8.0 atau yang lebih tinggi, Anda tidak dapat menggunakan manifes untuk mendeklarasikan penerima untuk sebagian besar siaran implisit (siaran yang tidak menargetkan aplikasi Anda). Anda masih dapat menggunakan penerima yang terdaftar dalam konteks jika pengguna aktif menggunakan aplikasi Anda.

Android 7.0

Android 7.0 (API level 24) dan yang lebih tinggi tidak mengirim sistem berikut siaran:

Selain itu, aplikasi yang menargetkan Android 7.0 dan yang lebih tinggi harus mendaftarkan siaran CONNECTIVITY_ACTION menggunakan registerReceiver(BroadcastReceiver, IntentFilter). Menyatakan penerima dalam manifes tidak akan berfungsi.

Menerima siaran

Aplikasi dapat menerima siaran dengan dua cara: melalui penerima yang dideklarasikan manifes dan penerima yang terdaftar dalam konteks.

Penerima yang dinyatakan manifes

Jika Anda mendeklarasikan penerima siaran dalam manifes, sistem akan meluncurkan (jika aplikasi belum berjalan) saat siaran dikirim.

Untuk menyatakan penerima siaran dalam manifes, lakukan langkah-langkah berikut:

  1. Tentukan <receiver> dalam manifes aplikasi Anda.

    <!-- 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="APP_SPECIFIC_BROADCAST" />
        </intent-filter>
    </receiver>
    

    Filter intent akan menentukan tindakan siaran yang menjadi langganan penerima Anda.

  2. Sediakan subclass BroadcastReceiver dan implementasikan onReceive(Context, Intent). Tujuan penerima siaran dalam contoh log berikut dan menampilkan kontennya dari siaran:

    Kotlin

    private const val TAG = "MyBroadcastReceiver"
    
    class MyBroadcastReceiver : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            StringBuilder().apply {
                append("Action: ${intent.action}\n")
                append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n")
                toString().also { log ->
                    Log.d(TAG, log)
    
                    val binding = ActivityNameBinding.inflate(layoutInflater)
                    val view = binding.root
                    setContentView(view)
    
                    Snackbar.make(view, log, Snackbar.LENGTH_LONG).show()
                }
            }
        }
    }
    

    Java

    public class MyBroadcastReceiver extends BroadcastReceiver {
            private static final String TAG = "MyBroadcastReceiver";
            @Override
            public void onReceive(Context context, Intent intent) {
                StringBuilder sb = new StringBuilder();
                sb.append("Action: " + intent.getAction() + "\n");
                sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
                String log = sb.toString();
                Log.d(TAG, log);
    
                ActivityNameBinding binding =
                        ActivityNameBinding.inflate(layoutInflater);
                val view = binding.root;
                setContentView(view);
    
                Snackbar.make(view, log, Snackbar.LENGTH_LONG).show();
            }
        }
    

    Untuk mengaktifkan view binding, mengonfigurasi viewBinding di level modul build.gradle Anda.

Pengelola paket sistem akan mendaftarkan penerima setelah aplikasi terinstal. Penerima kemudian menjadi titik entri terpisah ke aplikasi Anda, yang berarti bahwa sistem dapat memulai aplikasi dan mengirimkan siaran jika aplikasi tidak sedang berjalan.

Sistem membuat komponen BroadcastReceiver baru untuk menangani setiap siaran yang diterimanya. Objek ini hanya valid selama durasi panggilan ke onReceive(Context, Intent). Setelah kode Anda kembali dari metode ini, sistem menganggap komponen tidak lagi aktif.

Penerima yang terdaftar dalam konteks

Penerima yang terdaftar dalam konteks akan menerima siaran selama pendaftaran mereka konteks tersebut valid. Misalnya, jika Anda mendaftar dalam Activity , Anda akan menerima siaran selama aktivitas tersebut tidak dimusnahkan. Jika Anda mendaftar dalam konteks Aplikasi, Anda akan menerima siaran selama aplikasi sedang berjalan.

Untuk mendaftarkan penerima dalam konteks, lakukan langkah-langkah berikut:

  1. Dalam file build level modul aplikasi, sertakan versi 1.9.0 atau yang lebih tinggi library AndroidX Core:

    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. Buat instance dari BroadcastReceiver:

    Kotlin

    val br: BroadcastReceiver = MyBroadcastReceiver()
    

    Java

    BroadcastReceiver br = new MyBroadcastReceiver();
    
  3. Buat instance dari IntentFilter:

    Kotlin

    val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
    

    Java

    IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
    
  4. Pilih apakah penerima siaran harus diekspor dan dapat dilihat aplikasi lain pada perangkat. Jika penerima ini memproses siaran yang dikirim dari sistem atau dari aplikasi lain—bahkan aplikasi lain yang Anda miliki—menggunakan RECEIVER_EXPORTED. Jika sebaliknya, penerima ini hanya mendengarkan yang dikirim oleh aplikasi Anda, gunakan flag RECEIVER_NOT_EXPORTED.

    Kotlin

    val listenToBroadcastsFromOtherApps = false
    val receiverFlags = if (listenToBroadcastsFromOtherApps) {
        ContextCompat.RECEIVER_EXPORTED
    } else {
        ContextCompat.RECEIVER_NOT_EXPORTED
    }
    

    Java

    boolean listenToBroadcastsFromOtherApps = false;
    if (listenToBroadcastsFromOtherApps) {
        receiverFlags = ContextCompat.RECEIVER_EXPORTED;
    } else {
        receiverFlags = ContextCompat.RECEIVER_NOT_EXPORTED;
    }
    
  5. Daftarkan penerima dengan memanggil registerReceiver():

    Kotlin

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

    Java

    ContextCompat.registerReceiver(context, br, filter, receiverFlags);
    
  6. Untuk berhenti menerima siaran, panggil unregisterReceiver(android.content.BroadcastReceiver). Pastikan untuk membatalkan pendaftaran penerima saat Anda tidak lagi membutuhkannya atau konteksnya sudah tidak valid.

    Perhatikan di mana Anda mendaftar dan membatalkan pendaftaran penerima, misalnya, jika mendaftarkan penerima di onCreate(Bundle) menggunakan konteks aktivitas, Anda harus membatalkan pendaftarannya di onDestroy() untuk mencegah kebocoran penerima keluar dari konteks aktivitas. Jika Anda mendaftar penerima di onResume(), Anda seharusnya membatalkan pendaftaran di onPause() untuk mencegah mendaftarkannya beberapa kali (Jika Anda tidak ingin menerima siaran saat dijeda, dan dapat mengurangi overhead sistem yang tidak perlu). Larangan membatalkan pendaftaran di onSaveInstanceState(Bundle), karena metode ini tidak dipanggil jika pengguna kembali ke tumpukan histori.

Efek pada status proses

Apakah BroadcastReceiver beroperasi atau tidak mempengaruhi proses yang ada di dalamnya, yang dapat mengubah kemungkinan {i>system-killing<i}. Proses latar depan menjalankan metode onReceive() penerima. Tujuan sistem akan menjalankan proses, kecuali dalam tekanan memori yang ekstrem.

BroadcastReceiver dinonaktifkan setelah onReceive(). Host penerima proses hanya sepenting komponen aplikasinya. Jika proses tersebut hanya menghosting penerima yang dideklarasikan manifes (kemunculan yang sering untuk aplikasi yang tidak pernah dilakukan pengguna atau belum berinteraksi), sistem dapat menghentikannya setelah onReceive() untuk sumber daya yang tersedia untuk proses penting lainnya.

Dengan demikian, penerima siaran tidak boleh memulai thread latar belakang yang berjalan lama. Sistem dapat menghentikan proses kapan saja setelah onReceive() untuk mengklaim kembali memori, yang menghentikan thread yang dibuat. Agar proses tetap berjalan, jadwalkan JobService dari penerima menggunakan JobScheduler agar sistem mengetahui bahwa proses masih berjalan. Ringkasan Pekerjaan Latar Belakang memberikan detail selengkapnya.

Mengirimkan siaran

Android memberikan tiga cara bagi aplikasi untuk mengirim siaran:

  • sendOrderedBroadcast(Intent, String) mengirimkan siaran ke satu penerima pada satu waktu. Saat setiap penerima dieksekusi pada gilirannya, {i>metadata<i} bisa menyebarkan hasil ke penerima berikutnya, atau dapat membatalkan siaran secara keseluruhan sehingga tidak akan diteruskan ke penerima. Urutan penerima yang berjalan dapat dikontrol dengan atribut android:priority pada filter intent yang cocok; penerima dengan prioritas yang sama akan dijalankan dalam urutan acak.
  • Metode sendBroadcast(Intent) mengirim {i>broadcast <i}ke semua penerima dalam urutan yang tidak ditentukan. Hal ini disebut Normal Siarkan. Ini lebih efisien, tetapi berarti penerima tidak dapat membaca dari penerima lain, menyebarkan data yang diterima dari siaran, atau membatalkan siaran.

Cuplikan kode berikut menunjukkan cara mengirim siaran dengan membuat Intent dan memanggil sendBroadcast(Intent).

Kotlin

Intent().also { intent ->
    intent.setAction("com.example.broadcast.MY_NOTIFICATION")
    intent.putExtra("data", "Nothing to see here, move along.")
    sendBroadcast(intent)
}

Java

Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("data", "Nothing to see here, move along.");
sendBroadcast(intent);

Pesan siaran dikemas dalam objek Intent. String tindakan intent harus menyediakan sintaksis nama paket Java aplikasi dan secara unik mengidentifikasi acara siaran. Anda dapat melampirkan informasi tambahan ke intent dengan putExtra(String, Bundle). Anda juga dapat membatasi siaran ke sekumpulan aplikasi dalam organisasi yang sama dengan memanggil setPackage(String) pada intent.

Membatasi siaran dengan izin

Izin memungkinkan Anda membatasi siaran ke kumpulan aplikasi yang menyimpan izin akses tertentu. Anda dapat menerapkan pembatasan pada pengirim atau penerima siaran.

Mengirim dengan izin

Saat Anda memanggil sendBroadcast(Intent, String) atau sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle), Anda dapat menentukan izin akses. Hanya penerima yang telah meminta izin tersebut dengan tag di manifesnya (dan selanjutnya diberi izin akses jika berbahaya) dapat menerima siaran. Misalnya, kode berikut mengirim broadcast:

Kotlin

sendBroadcast(Intent(BluetoothDevice.ACTION_FOUND),
              Manifest.permission.BLUETOOTH_CONNECT)

Java

sendBroadcast(new Intent(BluetoothDevice.ACTION_FOUND),
              Manifest.permission.BLUETOOTH_CONNECT)

Untuk menerima siaran, aplikasi penerima harus meminta izin sebagai yang ditampilkan di bawah ini:

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

Anda dapat menentukan izin sistem yang ada seperti BLUETOOTH_CONNECT atau mendefinisikan izin khusus dengan Elemen <permission>. Sebagai tentang izin akses dan keamanan secara umum, lihat dokumentasi Sistem Izin.

Menerima dengan izin

Jika Anda menentukan parameter izin saat mendaftarkan penerima siaran (baik dengan registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) atau dalam Tag <receiver> di maka hanya penyiar yang telah meminta izin dengan Tag <uses-permission> di dalam manifesnya (dan selanjutnya diberi izin jika berbahaya) dapat mengirim Intent ke penerima.

Misalnya, anggap aplikasi penerima Anda memiliki penerima yang dideklarasikan manifes sebagai yang ditampilkan di bawah ini:

<receiver android:name=".MyBroadcastReceiver"
          android:permission="android.permission.BLUETOOTH_CONNECT">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_FOUND"/>
    </intent-filter>
</receiver>

Atau aplikasi penerima Anda memiliki penerima yang terdaftar dalam konteks seperti yang ditunjukkan di bawah ini:

Kotlin

var filter = IntentFilter(Intent.ACTION_FOUND)
registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null )

Java

IntentFilter filter = new IntentFilter(Intent.ACTION_FOUND);
registerReceiver(receiver, filter, Manifest.permission.BLUETOOTH_CONNECT, null );

Kemudian, agar dapat mengirim siaran ke penerima tersebut, aplikasi pengirim harus minta izin seperti yang ditunjukkan di bawah ini:

<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

Pertimbangan keamanan dan praktik terbaik

Berikut adalah beberapa pertimbangan keamanan dan praktik terbaik untuk mengirim dan menerima siaran:

  • Jika banyak aplikasi telah mendaftar untuk menerima siaran yang sama di manifes, itu dapat menyebabkan sistem meluncurkan banyak aplikasi, menyebabkan dampak besar pada kinerja perangkat dan pengalaman pengguna. Untuk menghindari ini, lebih suka menggunakan pendaftaran konteks daripada deklarasi manifes. Terkadang, sistem Android sendiri memberlakukan penggunaan penerima. Misalnya, siaran CONNECTIVITY_ACTION dikirim hanya untuk penerima yang terdaftar dalam konteks.

  • Jangan menyiarkan informasi sensitif menggunakan intent implisit. Tujuan informasi dapat dibaca oleh aplikasi apa pun yang mendaftar untuk menerima siaran. Ada tiga cara untuk mengontrol siapa saja yang dapat menerima siaran Anda:

    • Anda dapat menentukan izin saat mengirimkan siaran.
    • Pada Android 4.0 dan yang lebih tinggi, Anda dapat menentukan package dengan setPackage(String) saat mengirim . Sistem membatasi siaran ke kumpulan aplikasi yang mencocokkan dengan paketnya.
  • Saat mendaftarkan penerima, aplikasi apa pun dapat mengirim informasi siaran ke penerima aplikasi Anda. Ada beberapa cara untuk membatasi yang diterima aplikasi Anda:

    • Anda dapat menentukan izin saat mendaftarkan penerima siaran.
    • Untuk penerima yang dideklarasikan manifes, Anda dapat menyetel atribut android:diekspor menjadi "false" dalam manifes. Penerima tidak menerima siaran dari sumber di luar aplikasi.
  • Ruang nama untuk tindakan siaran bersifat global. Pastikan nama tindakan dan {i>string<i} lainnya ditulis dalam namespace milik Anda, atau Anda mungkin secara tidak sengaja bertentangan dengan aplikasi lain.

  • Karena metode onReceive(Context, Intent) penerima berjalan pada thread utama, ia akan dieksekusi dan kembali dengan cepat. Jika Anda ingin melakukan pekerjaan yang berjalan lama, berhati-hatilah saat menghasilkan utas atau memulai layanan latar belakang karena sistem dapat menghentikan seluruh proses setelah onReceive() ditampilkan. Untuk informasi selengkapnya, lihat Pengaruh pada proses status Untuk melakukan pekerjaan yang berjalan lama, kita rekomendasikan:

    • Menelepon goAsync() di metode onReceive() penerima dan meneruskan BroadcastReceiver.PendingResult ke thread latar belakang. Tindakan ini akan membuat siaran tetap aktif setelah kembali dari onReceive(). Namun, bahkan dengan pendekatan ini, sistem mengharapkan Anda untuk menyelesaikan siaran dengan sangat cepat (di bawah 10 detik). Hal ini memungkinkan Anda untuk memindahkan bekerja ke thread lain untuk menghindari gangguan pada thread utama.
    • Menjadwalkan tugas dengan JobScheduler. Untuk selengkapnya informasi, lihat Tugas Cerdas Penjadwalan.
  • Jangan memulai aktivitas dari penerima siaran karena pengalaman pengguna mengagetkan; terutama jika ada lebih dari satu penerima. Sebagai gantinya, pertimbangkan menampilkan notifikasi.