오늘은 브로드캐스트 리시버에 대해 공부했다.
이벤트 모델로 실행되는 컴포넌트. 줄여서 리시버
이벤트 : 사용자이벤트 x. 시스템의 특정한 상황
리시버도 안드로이드의 컴포넌트이므로 인텐트를 시스템에 전달함으로써 실행한다.
class MyReceiver: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
TODO("Not yet implemented")
}
}
리시버는 BroadcastReceiver
를 상속받는 클래스를 선언해야 한다.
생명주기 함수는 onReceiver() 하나 뿐이다. 어디에서 리시버를 실행시키려고 인텐틀르 시작하면 이 함수가 자동으로 호출된다. 그리고 자신을 호출한 intent 객체를 매개변수로 받는다.
onReceiver()함수는 실행 후 10초내에 완료할것을 권장하므로 오래걸리는 작업은 부적절하다.
onReceiver()함수가 실행을 마치면 리시버 객체는 소멸한다.
특정한 상황에 리시버를 항상 실행해야한다면, 매니페스트 파일에 등록해 사용한다.
태그는 <receiver>, 필수 속성은 name. 암시적 인텐트로 실행하려면 <intent-filter>를 선언해야한다.
<receiver android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
</receiver>
리시버는 매니페스트에 등록하지 않고 코드에서 필요한 순간에 동적으로 등록할 수도 있다. 특정 액티비티나 서비스가 동작할 때만 브로드캐스트 리시버를 실행해야한다면 동적으로 등록하는 방법을 사용한다.
// 리시버 객체 생성
val receiver = object: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
TODO("Not yet implemented")
}
}
// 동적 등록
val filter = IntentFilter("ACTION_RECEIVER")
registerReceiver(receiver,filter)
// 등록 해제
unregisterReceiver(receiver)
필요한 순간에 registerReceiver() 함수를 이용해 시스템에 등록한다.
사용 후, 필요없으면 unregisterReceiver() 함수를 이용해 해제해줘야 한다.
리시버를 실행하려면 인텐트가 필요하다. 클래스명만 등록했으면 명시적 인텐트로, 인텐트 필터를 등록했으면 암시적 인텐트로 실행한다.
리시버를 매니페스트 파일에 등록하고 <intent-filter> 태그를 선언했다면 암시적 인텐트로는 실행할 수 없다.
코드에서 registerReceiver() 함수로 등록한 리시버는 암시적 인텐트로도 잘 실행된다.
리시버를 실행하는 인텐트는 sendBroadcast()
함수로 시스템에 전달한다.
val intent = Intent(this, MyReceiver::class.java)
sendBroadcast(intent)
시스템에서 발생하는 인텐트는 여러 종류가 있다. 부팅완료, 화면on/off, 배터리 상태 등이 대표적이다.
부팅 완료시 특정 작업을 앱에서 수행하고 싶으면 리시버를 만들고 매니페스트 파일에 인텐트 필터를 구성해 등록한다.
부팅이 완료되면 시스템에서는 android.intent.action.BOOT_COMPLETED
라는 액션 문자열을 포함하는 인텐트가 발생한다.
리시버와 인텐트 필터 등록
매니페스트 상위에 퍼미션을 추가해야한다.
<uses-permission android:name="android.intent.action.BOOT_COMPLETED"/>
...
<receiver android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
화면을 켜거나 끄는 상황을 감지하는 브로드캐스트 리시버는 매니페스트에 등록하면 실행되지 않는다.
따라서, 액티비티나 서비스 컴포넌트의 코드에서 registerReceiver() 함수를 이용해 동적으로 등록해야 한다.
android.intent.action.SCREEN_ON
과 android.intent.action.SCREEN_OFF
액션 문자열을 상수 변수로 사용한다.
val receiver = object: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
when(intent?.action){
Intent.ACTION_SCREEN_ON -> Log.d("event", "화면 켜짐")
Intent.ACTION_SCREEN_OFF -> Log.d("event", "화면 꺼짐")
}
}
}
// 리시버 등록
val filter = IntentFilter(Intent.ACTION_SCREEN_ON).apply {
addAction(Intent.ACTION_SCREEN_OFF)
}
registerReceiver(receiver,filter)
// 리시버 등록 해제
unregisterReceiver(receiver)
현재 기기에 전원이 얼마나 공급되는지, 충전량은 얼마나 되는지 등을 나타낸다.
안드로이드 시스템에서 배터리 상태가 변경되면 다음 액션 문자열로 인텐트가 발생한다.
BATTERY_LOW: 배터리가 낮은 상태로 변경되는 순간
BATTERY_OKAY: 배터리가 정상 상태로 변경되는 순간
BATTERY_CHANGED: 충전 상태가 변경되는 순간
ACTION_POWER_CONNECTED: 전원이 공급되기 시작한 순간
ACTION_POWER_DISCONNECTED: 전원 공급을 끊은 순간
리시버 작성(시스템에서 상태가 변경(이벤트 발생)되었을때)
val receiver = object: BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
when(intent?.action){
Intent.ACTION_BATTERY_OKAY -> Log.d("event", "ACTION_BATTERY_OKAY")
Intent.ACTION_BATTERY_LOW -> Log.d("event", "ACTION_BATTERY_LOW")
Intent.ACTION_BATTERY_CHANGED -> Log.d("event", "ACTION_BATTERY_CHANGED")
Intent.ACTION_POWER_CONNECTED -> Log.d("event", "ACTION_POWER_CONNECTED")
Intent.ACTION_POWER_DISCONNECTED -> Log.d("event", "ACTION_POWER_DISCONNECTED")
}
}
}
// 리시버 등록
val filter = IntentFilter(Intent.ACTION_BATTERY_OKAY).apply {
addAction(Intent.ACTION_BATTERY_LOW)
addAction(Intent.ACTION_BATTERY_CHANGED)
addAction(Intent.ACTION_POWER_CONNECTED)
addAction(Intent.ACTION_POWER_DISCONNECTED)
}
registerReceiver(receiver,filter)
// 리시버 등록 해제
unregisterReceiver(receiver)
val intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
val batteryStatus = registerReceiver(null, intentFilter)
val status = batteryStatus!!.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
if (status==BatteryManager.BATTERY_STATUS_CHARGING){ //전원 공급상태
val chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
when(chargePlug){
// 저속충전
BatteryManager.BATTERY_PLUGGED_USB -> Log.d("event", "usb charge")
// 고속충전
BatteryManager.BATTERY_PLUGGED_AC -> Log.d("event", "ac charge")
}
}else{ // 전원 미공급상태
Log.d("event", "not charging")
}
val level = batteryStatus!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale = batteryStatus!!.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
val batteryPct = level/scale.toFloat() * 100
Log.d("event", "batteryPct : $batteryPct")