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:
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.
Sediakan subclass
BroadcastReceiver
dan implementasikanonReceive(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:
Dalam file build level modul aplikasi, sertakan versi 1.9.0 atau yang lebih tinggi library AndroidX Core:
Groovy
dependencies { def core_version = "1.13.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.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.13.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.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") }
Buat instance dari
BroadcastReceiver
:Kotlin
val br: BroadcastReceiver = MyBroadcastReceiver()
Java
BroadcastReceiver br = new MyBroadcastReceiver();
Buat instance dari
IntentFilter
:Kotlin
val filter = IntentFilter(APP_SPECIFIC_BROADCAST)
Java
IntentFilter filter = new IntentFilter(APP_SPECIFIC_BROADCAST);
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 flagRECEIVER_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; }
Daftarkan penerima dengan memanggil
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, br, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, br, filter, receiverFlags);
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 dionDestroy()
untuk mencegah kebocoran penerima keluar dari konteks aktivitas. Jika Anda mendaftar penerima dionResume()
, Anda seharusnya membatalkan pendaftaran dionPause()
untuk mencegah mendaftarkannya beberapa kali (Jika Anda tidak ingin menerima siaran saat dijeda, dan dapat mengurangi overhead sistem yang tidak perlu). Larangan membatalkan pendaftaran dionSaveInstanceState(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
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 setelahonReceive()
ditampilkan. Untuk informasi selengkapnya, lihat Pengaruh pada proses status Untuk melakukan pekerjaan yang berjalan lama, kita rekomendasikan:- Menelepon
goAsync()
di metodeonReceive()
penerima dan meneruskanBroadcastReceiver.PendingResult
ke thread latar belakang. Tindakan ini akan membuat siaran tetap aktif setelah kembali darionReceive()
. 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.
- Menelepon
Jangan memulai aktivitas dari penerima siaran karena pengalaman pengguna mengagetkan; terutama jika ada lebih dari satu penerima. Sebagai gantinya, pertimbangkan menampilkan notifikasi.