ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Broadcast Receiver 예제
    안드로이드 학습/Android 기술면접 대비 코드 2023. 6. 11. 09:03

    BroadCast의 기본 설명 링크

     

    Broadcast Receiver에서 받을수 있는 이벤트가 너무 많기 때문에 그중 일부를 알아보자면 아래와 같다.

    Broadcast Receiver에서 받을수 있는 이벤트:

    더보기
    ACTION_BOOT_COMPLETED
    부팅이 끝났을 때 (RECEIVE_BOOT_COMPLETED 권한등록 필요)

    ACTION_CAMERA_BUTTON
    카메라 버튼이 눌렸을 때

    ACTION_DATE_CHANGED
    ACTION_TIME_CHANGED
    폰의 날짜, 시간이 수동으로 변했을때 (설정에서 수정했을때)


    ACTION_SCREEN_OFF
    ACTION_SCREEN_ON
    화면 on, off

    ACTION_AIRPLANE_MODE_CHANGED
    비행기 모드

    ACTION_BATTERY_CHANGED
    ACTION_BATTERY_LOW
    ACTION_BATTERY_OKAY
    배터리 상태변화


    ACTION_PACKAGE_ADDED
    ACTION_PACKAGE_CHANGED
    ACTION_PACKAGE_DATA_CLEARED
    ACTION_PACKAGE_INSTALL
    ACTION_PACKAGE_REMOVED
    ACTION_PACKAGE_REPLACED
    ACTION_PACKAGE_RESTARTED
    어플 설치/제거

    ACTION_POWER_CONNECTED
    ACTION_POWER_DISCONNECTED
    충전 관련

    ACTION_REBOOT
    ACTION_SHUTDOWN
    재부팅/종료

    ACTION_TIME_TICK
    매분마다 수신

    android.provider.Telephony.SMS_RECEIVED
    sms 수신 (RECEIVE_SMS 권한 필요)

    이런 것들 말고도 앱내에서 개발자가 직접 발송해서 받을 수도 있다. 

     

    여러가지 이벤트들 중에 쉽게 표시가 나는 이벤트를 택해서 예제에 넣어봤다.

    ACTION_BATTERY_CHANGED : 배터리 상태변화

    ACTION_POWER_CONNECTED : 배터리 충전중?
    ACTION_POWER_DISCONNECTED : 배터리 안충전중?

    그리고  Broadcast Receiver는 정적 리시버(Static Receiver)와 동적 리시버(Dynamic Receiver)로 두 가지 형태로 나뉜다.

     

    정적 리시버 

    정적 리시버는 사용할 수 있는 것의 제한이 있다. 

     

    "Android 8.0(API 레벨 26) 백그라운드 실행 제한의 일환으로 API 레벨 26 이상을 타겟팅하는 앱은 암시적 브로드캐스트의 broadcast receiver를 manifest에 더 이상 등록할 수 없습니다. 하지만 현재 몇몇 브로드캐스트는 이러한 제한에서 제외됩니다. 앱이 타겟팅하는 API 레벨과 관계없이 앱은 다음 브로드캐스트의 리스너를 계속 등록할 수 있습니다."


    참고 : https://developer.android.com/guide/components/broadcast-exceptions?hl=ko

     

    1. MyBroadcastReceiver에서 이벤트 받는 부분

    class MyBroadcastReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent) {
            Toast.makeText(context, intent.action, Toast.LENGTH_SHORT).show()
            Log.d("LocaleChangedRecevier", "onReceive: receive 받기: ${intent.action}")
    
            when (intent.action) {
                "custom.MyStaticAction" -> {
                    Toast.makeText(context, "custom.MyStaticAction", Toast.LENGTH_SHORT).show()
                }
                Intent.ACTION_BOOT_COMPLETED -> {
                    Toast.makeText(context, "ACTION_BOOT_COMPLETED", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    2. 테스트를 위해 동적으로 Receiver 실행

    class MainActivity : AppCompatActivity() {
    
        @RequiresApi(Build.VERSION_CODES.O)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
    		... 생략 ...
    
            staticReceiverBtn.setOnClickListener{
                val intent = Intent(this, MyBroadcastReceiver::class.java)
                intent.action = "custom.MyStaticAction"
                sendBroadcast(intent)
            }
    
    		... 생략 ...
    
        }

    3. AndroidManifest.xml 등록

     <application
     
      		... 생략 ...
            
            <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.ACTION_BOOT_COMPLETED" />
                </intent-filter>
            </receiver>
    
      		... 생략 ...
    
        </application>

     

    동적 리시버  

    1. 동적 리시버 등록

        private fun dynamicBroadcastReceiverInitialze(){
            intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
            intentFilter.addAction("custom.MyDynamicAction")
    
            receiver = object: BroadcastReceiver() {
                override fun onReceive(context: Context, intent: Intent) {
                    val action = intent.action
    
                    when (action) {
                        Intent.ACTION_BATTERY_CHANGED -> {
                            Toast.makeText(context, "ACTION_BATTERY_CHANGED", Toast.LENGTH_SHORT).show()
                        }
                        "custom.MyDynamicAction" -> {
                            Toast.makeText(context, "custom.MyDynamicAction", Toast.LENGTH_SHORT).show()
                        }
                    }
                }
            }
        }

    2. 테스트를 위해 동적으로 실행

            dynamicReceiverBtn.setOnClickListener{
                val intent = Intent("custom.MyDynamicAction")
                sendBroadcast(intent)
            }

     

     

    전체 예제 :  정적 + 동적 리시버

    AndroidManifest.xml

    더보기
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    
        <application
            android:allowBackup="true"
            android:dataExtractionRules="@xml/data_extraction_rules"
            android:fullBackupContent="@xml/backup_rules"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.BroadcaseReceiver"
            tools:targetApi="31">
    
            <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.ACTION_BOOT_COMPLETED" />
                </intent-filter>
            </receiver>
            <activity
                android:name=".MainActivity"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
        </application>
    
    </manifest>

    MainActivity.kt

    더보기
    class MainActivity : AppCompatActivity() {
    
        private lateinit var receiver: BroadcastReceiver
        private lateinit var staticReceiverBtn: Button
        private lateinit var dynamicReceiverBtn: Button
    
        private val intentFilter = IntentFilter()
    
        @RequiresApi(Build.VERSION_CODES.O)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            staticReceiverBtn = findViewById(R.id.staticReceiverBtn)
            dynamicReceiverBtn =  findViewById(R.id.dynamicReceiverBtn)
    
            staticReceiverBtn.setOnClickListener{
                val intent = Intent(this, MyBroadcastReceiver::class.java)
                intent.action = "custom.MyStaticAction"
                sendBroadcast(intent)
            }
    
            dynamicReceiverBtn.setOnClickListener{
                val intent = Intent("custom.MyDynamicAction")
                sendBroadcast(intent)
            }
    
            dynamicBroadcastReceiverInitialze()
        }
    
        override fun onStart() {
            super.onStart()
            registerReceiver(receiver, intentFilter);
        }
    
        override fun onDestroy() {
            super.onDestroy()
            unregisterReceiver(receiver)
        }
    
        private fun dynamicBroadcastReceiverInitialze(){
            intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
            intentFilter.addAction("custom.MyDynamicAction")
    
            receiver = object: BroadcastReceiver() {
                override fun onReceive(context: Context, intent: Intent) {
                    val action = intent.action
    
                    when (action) {
                        Intent.ACTION_BATTERY_CHANGED -> {
                            Toast.makeText(context, "ACTION_BATTERY_CHANGED", Toast.LENGTH_SHORT).show()
                        }
                        "custom.MyDynamicAction" -> {
                            Toast.makeText(context, "custom.MyDynamicAction", Toast.LENGTH_SHORT).show()
                        }
                    }
                }
            }
        }

    activity_main.xml

    더보기
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/staticReceiverBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="60dp"
            android:layout_marginTop="500dp"
            android:text="정적 리시버"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <Button
            android:id="@+id/dynamicReceiverBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="500dp"
            android:layout_marginEnd="60dp"
            android:text="동적 리시버"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>

    MyBroadcastReceiver.kt

    더보기
    class MyBroadcastReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent) {
            Toast.makeText(context, intent.action, Toast.LENGTH_SHORT).show()
            Log.d("LocaleChangedRecevier", "onReceive: receive 받기: ${intent.action}")
    
            when (intent.action) {
                "custom.MyStaticAction" -> {
                    Toast.makeText(context, "custom.MyStaticAction", Toast.LENGTH_SHORT).show()
                }
                Intent.ACTION_BOOT_COMPLETED -> {
                    Toast.makeText(context, "ACTION_BOOT_COMPLETED", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    결과 :

    충전중일때  정적 리시버 버튼 눌렀을 때 동적 리시버 버튼 눌렀을 때

     

    아...... 이런 쉬운 예제도 만드는데 5시간이 걸렸다...... 동적 리시버는 금방 됐는데 정적 리시버가 계속 안되서 찾아보니 이제는 몇가지 말고는 정적 리시버로 등록이 불가능한것 같다. 문서를 정독하는 습관을 길러야겠다.......

Designed by Tistory.