시스템이 방송한 정보를 수신하고 해당 상황에 대한 동작을 정의할 수 있는 컴포넌트.
전화가 걸려옴에 의한 알림 - 전화 앱 실행 동작과 연결
배터리 부족에 의한 알림 - 실행 중인 앱들 정보 저장 동작과 연결
시스템 뿐만 아니라 여러 앱들이 방송을 보낼 수 있다.
앱들은 관심 있는 방송에 대해 Receiver를 정의하여 방송들을 선택해서 수신할 수 있다.
val intent = Intent().apply {
action = "com.ich.test.broadcasting.action.FILE_DOWNLOAD"
putExtra("FILE_NAME","test_file")
}
sendBroadcast(intent)
Intent에 action과 extra 등 정보를 추가한 후 sendBroadcast 함수를 이용하여 전송.
보내는 쪽에서 정의한 action을 받을 앱의 receiver에 intent-filter로 추가하면 해당 방송을 수신할 수 있다
시스템 방송에 대한 플래그(배터리 or 화면 켜짐 등 다양)도 기본적으로 존재하므로 해당 플래그로 등록할 경우 시스템 방송을 수신할 수 있다.
+) 시스템 방송들 중 일부는 부하를 막기 위해 동적 리시버만 수신하도록 한 것들도 존재한다.
class TestReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val fileName = intent.getStringExtra("FILE_NAME")
Toast.makeText(context, "name: $fileName", Toast.LENGTH_SHORT).show()
}
}
/// Manifest.xml
<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="com.ich.test.broadcasting.action.FILE_DOWNLOAD"
</intent-filter>
</receiver>
위처럼 BroadcastReceiver를 상속받은 클래스를 생성하고, 방송에 대한 동작을 위한 onReceive 함수를 재정의한다.
이후 Manifest에서 컴포넌트 레벨(액티비티와 동일한 레벨)에 리시버를 정의하고 생성한 Receiver 클래스를 넣는다.
추가로, 정적 리시버는 동시에 처리되지 않고 순차적으로 처리된다.
따라서 한 리시버의 처리가 늦어지면 다음 리시버들의 처리도 늦어진다.

val intentFilter = IntentFilter()
intentFilter.addAction("com.ich.test.broadcasting.action.FILE_DOWNLOAD")
val receiver = object: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val fileName = intent.getStringExtra("FILE_NAME")
Toast.makeText(context, "name: $fileName", Toast.LENGTH_SHORT).show()
}
}
registerReceiver(receiver, intentFilter)
위처럼 Maniest 정의 없이 IntentFilter와 BroadcastReceiver 객체를 생성하고, registerReceiver 함수를 이용하여 리시버를 등록한다.
동적 리시버는 다른 컴포넌트, 주로 액티비티에서 등록하므로 컴포넌트의 생명 주기가 끝나면 동작하지 않는다.
따라서 메모리 누수를 방지하기 위해 컴포넌트의 생명주기에 맞춰 등록을 해제하는 과정이 필요하다.
액티비티의 경우 onDestroy() 생명주기 함수에서 unRegisterReceiver 함수를 호출하여 리시버를 해제한다.
추가로, 동적 리시버는 동시에 처리될 수 있다.
5개의 리시버를 1~5순서로 등록한 후 처리하는 경우, 1~5순서로 리시버가 호출된다.
하지만 동시에 처리되기 때문에 처리 완료시간은 호출 순서와 달라질 수 있다.

+) 동적 리시버를 순서대로 처리하게 하고 싶다면 sendBroadcast함수 대신 sendOrderedBroadcast함수를 사용하면 된다.
사용자가 의도하지 않게 모든 시스템 방송을 수신하여 부하를 받게 되거나, 리시버를 통해 정보를 빼가기 위한 악의적인 앱 등을 방지하기 위해 플래그가 존재한다.
아래 플래그들은 intent.addFlags 함수로 추가할 수 있다.
FLAG_EXCLUDE_STOPPED_PACKAGES (기본 설정)
한 번이라도 실행되어야 해당 앱의 정적 리시버가 동작할 수 있다.
FLAG_INCLUDE_STOPPED_PACKAGES
위 동작과 반대로, 실행되지 않은 앱의 리시버가 동작할 수 있도록 한다.
FLAG_RECEIVER_REGISTERED_ONLY
동적 리시버만 방송을 수신할 수 있도록 한다. (특정 앱 정적 리시버가 몰래 실행되는 것 방지)
FLAG_RECEIVER_REPLACE_PENDING
중복해서 동일한 액션으로 방송될 경우 중복을 제거한다.
FLAG_RECEIVER_FOREGROUND
방송을 Foreground로 설정하여 우선 처리를 요구하도록 보낸다.
BroadcastReceiver는 메인 스레드에서 처리되는 컴포넌트이다.
따라서 ANR이 발생할 수 있다.
Foreground Receiver의 경우 10초
Background Receiver의 경우 60초
ANR 발생 시간이 존재한다.
위에서 언급하였다시피 Receiver는 메인 스레드 동작이므로 오래 걸리는 작업을 넣어 두면 액티비티에도 영향을 줄 수 있다.
오래 걸리는 작업을 해야 한다면 스레드 또는 서비스를 사용하자.
Global Broadcast는 다음의 문제점들이 있다.
다른 앱에 Broadcast를 보낼 필요가 없을 경우 Broadcast를 발송시킨 앱 밖으로 내보내지 않도록 하는 것이 LocalBroadcast이다.
LocalBroadcastManager 객체를 통해 인스턴스를 얻어올 수 있으며 사용 방법은 유사하다.
// 송신
val intent = Intent().apply {
action = "com.ich.test.broadcasting.action.LOCAL_BROADCAST"
}
val broadcastManager = LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
//수신
val intentFilter = IntentFilter()
intentFilter.addAction("com.ich.test.broadcasting.action.LOCAL_BROADCAST")
val receiver = object: BroadcastReceiver(){
override fun onReceive(context: Context, intent: Intent) {
// 처리
}
}
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter)