14. [브로드캐스트 리시버 컴포넌트]

728x90

[14. 브로드캐스트 리시버 컴포넌트]

[14-1. 브로드캐스트 리시버 이해하기]

[브로드캐스트 리시버] : 안드로이드 4개의 컴포넌트 하나

-브로드캐스트 리시버 : ‘시스템 이벤트발생 시, 실행되는 컴포넌트

              , 시스템에 특정 이벤트 발생 시, 알림을 받아서 처리하는 수신기

     -이 역시 안드로이드의 컴포넌트. 따라서 인텐트를 시스템에 전달하여 실행 O

     -안드로이드 컴포넌트는 매니페스트에 등록해야 시스템이 인지O

[브로드캐스트 리시버 생성]

  (1) ‘일반생성 방법

        ① 브로드캐스트 리시버 객체 생성

-BroadcastReceiver 상속받는 클래스 선언

-내부에 유일한 생명주기 함수 onReceive() 함수가 자동 호출/소멸됨

         매니페스트 파일에 <receiver> 태그로 등록

<실행할 인텐트 지정>

명시적 인텐트로 실행 -> 클래스명만 등록 
암시적 인텐트로 실행 -> <intent-fileter> 선언 필수

  (2) ‘동적생성 방법

        브로드캐스트 리시버 객체 생성

        코드에서 registerReceiver() 함수로 시스템에 등록

           -등록 위치 : 액티비티 or 서비스 컴포넌트의 코드에 함수로 등록

           -매니페스트 파일에 <receiver>로 등록되어있지 않아도 시스템에서 리시버 존재 인지함

        코드에서 unregisterReceiver() 함수로 해제

               -사용한 후 필요없으면 해제 필수


[브로드캐스트 리시버 실행]

-실행을 위해서는 인텐트필요

-시스템에 리시버 등록 시,

1) 명시적. 클래스명만 등록했다 -> 클래스 타입 래퍼런스 이용하여 실행

2) 암시적. 인텐트 필터로 등록했다. -> 암시적 인텐트로 실행

   -인텐트는 실행할 브로드캐스트 리시버를 sendBroadcast() 함수로 시스템에 전달함
   -시스템은 브로드캐스트 리시버 객체 생성하여 실행해줌

-'없으면 말고 있으면 모두 실행'하는 독특한 동작원리

-시스템에 해당 인텐트로 실행될 리시버 없어도 오류 발생 X. 여러 개 있으면 모두 실행 O


[14-2. 시스템 상태 파악]

구조 : 시스템 상태변화(이벤트 발생) -> 인텐트 발생(리시버 호출) -> 리시버 실행

-시스템에서 발생하는 인텐트 종류 

[부팅 완료 상태]

    ① 부팅 완료되면

       시스템에서 ’android.intent.action.BOOT_COMPLETED‘ 액션문자열 포함 인텐트 발생

    ② 이때 실행할 리시버등록 시, <action> name 속성에 똑같은 액션문자열 지정 필수

<receiver
  android:name = ‘.MyReceiver“
  android:enabled=“true”
  android:exported=“true”
  <intent-filter>
    <action android:name=“android.intent.action.BOOT_COMPLETED”/>
  </intent-filter>
</receiver>

     리시버 실행 권한 필요 : 메니페스트에 퍼미션 추가

<uses-permission android:name=“android.permission.RECEIVE_BOOT_COMPLETED”/>

[화면 켬/끔 상태]

-화면 켬/끔 상황 감지 브로드캐스트 리시버는 매니페스트 파일 등록 시 실행 불가능

-따라서, 액티비티 or 서비스 컴포넌트에서 registerReceiver() 함수로 동적 등록 필수

   <화면 켬>
시스템에서 ’android.intent.action.SCREEN_ON‘ 액션문자열 포함 인텐트 발생
   <화면 끔>
시스템에서 ‘android.intent,action.SCREEN_OFF’ 액션문자열 포함 인텐트 발생

    ① 화면 켬/끔 상태 판단

-리시버는 자신을 호출한 Intent 객체의 액션 문자열을 토대로 상태 판단 O

receiver = object : BroadcastReceiver() {
   override fun onReceive(context: Context?, intent: Intent?) { 
      when(intent?.action) {
         Intent.ACTION_SCREEN_ON -> Log.d(“kkang”, “screen on”)  //켤 때
         Intent.ACTION_SCREEN_OFF -> Log.d(“kkang”, “screen off”) //끌 때
      }
   }
}

    ② 브로드캐스트 리시버동적 등록

-리시버는 액션문자열 정보 구성한 인텐트 필터와 함께 시스템에 등록함

val filter = IntentFilter(Intent.ACTION_SCREEN_ON).apply{  //이 인텐트 액션 발생 시 실행되어야 하니ᄁᆞ
     addAction(Intent.ACTION_SCREEN_OFF)
}
registerReceiver(receiver, filter) //리시버 등록

등록 해제 : unregisterReceiver(receiver) 로 등록 해제함


[배터리 상태]

-기본적으로 시스템 상태 변경으로 인한 인텐트발생 시 리시버가 실행됨

   ① 시스템 배터리 상태 변화에 따른 관련 액션 문자열인텐트 발생

                   <배터리 관련 인텐트 액션 문자열>

BATTERY_LOW 배터리 낮은상태로 변경되는 순간
BATTERY_OKAY 배터리 정상상태로 변경되는 순간
BATTERY_CHANGED 충전 상태 변경되는 순간
BATTERY_POWER_CONNECTED 전원 공급 시작되는 순간
BATTERY_DISCONNECTED 전원 공급 끝난순간

     관련 액션 문자열 상태별. 실행될 브로드캐스트 리시버 작성

receiver = object : BroadcastReceiver() {
     override fun onReceive(context: Context?, intent: Intent?) {
        when(intent?.action) {
             Intent.ACTION_BATTERY_OKAY -> Log.d(“kkang”, “ACTION_BATTERY_OKAY”)
             Intent.ACTION_BATTERY_LOW -> Log.d(“kkang”, “ACTION_BATTERY_LOW”)
             Intent.ACTION_BATTERY_CHANGED -> Log.d(“kkang”, “ACTION_BATTERY_CHANGED”)
             Intent.ACTION_BATTERY_CONNECTED -> Log.d(“kkang”, “ACTION_BATTERY_CONNECTED”)
             Intent.ACTION_BATTERY_DISCONNECTED -> Log.d(“kkang”, “ACTION_BATTERY_DISCONNECTED”)
        }
    }
}

    ③ 해당 액션 문자열 인텐트 발생 시, 실행될 리시버를 시스템에 등록

val filter = IntentFilter(Intent.ACTION_BATTERY_LOW).apply {
    addAction(Intent.ACTION_BATTERY_OKAY) 
    addAction(Intent.ACTION_BATTERY_CHANGED)
    addAction(Intent.ACTION_POWER_CONNECTED)
    addAction(Intent.ACTION_POWER_DISCONNECTED)
}
registerReceiver(receiver, filter)  //시스템에 리시버 등록

[시스템 상태 변경 없이도 상태 파악‘]

-기본적으로 리시버는 시스템 상태 변경되어 인텐트 발생시켜줘야만 실행이 됨

-BUT. 시스템 상태 변경 없이도 배터리 상태 파악 가능하기도 함

  (1) 액션문자열 ’Intent.ACTION_BATTERY_CHANGED’ 로 지정한 IntentFilter 객체 만들고

  (2) 인텐트의 엑스트라 정보 이용하여 registerReceiver() 함수로 리시버 등록

val intentFilter = IntentFileter(Intent.ACTION_BATTERY_CHANGED)
val batteryStatus = registerReceiver(null, intentFilter)

<< 인텐트의 엑스트라 정보 이용 -> 배터리 상태 파악 >>

[현재 전원 공급 여부 상태 파악]

-BatteryManager.EXTRA_STATUS 로 얻는 엑스트라값으로 알 수 있음

BatteryManager.BATTERY_STATUS_CHARGING 전원 공급되는 상태

[이미 전원 공급 상태에 한해서 -> 다시 현재 충전 상태 파악’]

-BatteryManager.EXTRA_PLUGGED 로 얻는 엑스트라값으로 알 수 있음

BatteryManager.EXTRA_PLUGGED_USB 저속 충전 상태
BatteryManager.BATTERY_PLUGGED_AC 고속 충전 상태

[배터리 충전량 상태 파악]

val level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
val batteryPct = level/scale.toFloat() * 100 // %로 출력가능
Log.d(“kkang”, “batteryPct : $batteryPct”)

[14-3. 배터리 정보 앱 만들기] : 실습

현재 배터리 상태 파악하여 결과를 화면에 출력 -> 화면에서 버튼 클릭 시 -> 브로드캐스트 리시버 실행하는 코드 

class MainActivity : AppCompatActivity() { //메인 액티비티 
        
    override fun onCreate(savedInstanceState: Bundle?) {   //실행 함수 
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        //add......................
        registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))!!.apply {  //리시버 등록 함수 (액션 문자열 -> 배터리 상태 변화 시) 실행될 리시버임  
            when (getIntExtra(BatteryManager.EXTRA_STATUS, -1)) { //현재 전원 공급 여부 확인용 엑스트라값 get 함
                BatteryManager.BATTERY_STATUS_CHARGING -> { // (1) 현재 전원 공급 상태 O 

                    when (getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)) {  //(전원 공급상태에 한해서) 현재 충전량 확인용 엑스트라값 다시 get함 
                        BatteryManager.BATTERY_PLUGGED_USB -> {   // ->  현재 '저속 충전 상태' 
                            binding.chargingResultView.text = "USB Plugged"
                            binding.chargingImageView.setImageBitmap(
                                BitmapFactory.decodeResource(resources, R.drawable.usb))
                        }
                        BatteryManager.BATTERY_PLUGGED_AC -> {    // -> 현재 '고속 충전 상태' 
                            binding.chargingResultView.text = "AC Plugged"
                            binding.chargingImageView.setImageBitmap(
                                BitmapFactory.decodeResource(resources, R.drawable.ac))
                        }
                    }
                }
                else -> {                                                //(2) 현재 전원 공급 상태 X
                    binding.chargingResultView.text = "Not Plugged"
                }
            }
            val level = getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
            val scale = getIntExtra(BatteryManager.EXTRA_SCALE, -1)
            val batteryPct = level / scale.toFloat() * 100
            binding.percentResultView.text = "$batteryPct %"
        }

        binding.button.setOnClickListener {   //버튼 클릭 이벤트 연결 
            val intent = Intent(this, MyReceiver::class.java)
            sendBroadcast(intent)
        }
    }
}

 

[참고] : Do It 안드로이드 앱 프로그래밍 with 코틀린 

728x90