본문 바로가기

Android

[Android] Lifecycle-aware BroadcastReceiver 구현하기

import android.content.BroadcastReceiver
import android.content.IntentFilter
import androidx.activity.ComponentActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.launch

/**
 * 주어진 Lifecycle 상태 이상일 때만 BroadcastReceiver를 등록하고,
 * 상태가 내려가면 자동으로 해제하는 Lifecycle-aware 유틸리티 함수입니다.
 *
 * LifecycleOwner의 repeatOnLifecycle 블록에서 동작하므로, 안전하게 register/unregister를 관리합니다.
 *
 * 사용 예시1: Activity
 * ```
 * registerReceiverWithLifecycle(
 *     state = Lifecycle.State.RESUMED,
 *     receiverProducer = {
 *         object : BroadcastReceiver() {
 *             override fun onReceive(context: Context?, intent: Intent?) {
 *                 val level = intent?.getIntExtra("level", -1)
 *                 Log.d("BatteryReceiver", "Battery level: $level")
 *             }
 *         }
 *     },
 *     intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED),
 *     flags = ContextCompat.RECEIVER_EXPORTED
 * )
 * ```
 * 사용 예시2: Fragment
 * ```
 * requireActivity().registerReceiverWithLifecycle(
 *     ownerProducer = { viewLifecycleOwner },
 *     state = Lifecycle.State.RESUMED,
 *     receiverProducer = {
 *         object : BroadcastReceiver() {
 *             override fun onReceive(context: Context?, intent: Intent?) {
 *                 val level = intent?.getIntExtra("level", -1)
 *                 Log.d("BatteryReceiver", "Battery level: $level")
 *             }
 *         }
 *     },
 *     intentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED),
 *     flags = ContextCompat.RECEIVER_EXPORTED
 * )
 * ```
 *
 * @param ownerProducer LifecycleOwner를 반환하는 람다입니다. 기본값은 현재 Activity입니다.
 * @param state receiver가 활성화될 최소 Lifecycle 상태입니다. 예: Lifecycle.State.STARTED
 * @param receiverProducer BroadcastReceiver 인스턴스를 생성하는 람다입니다.
 * @param intentFilter 등록할 IntentFilter입니다.
 * @param flags registerReceiver에 전달될 플래그입니다. 예: ContextCompat.RECEIVER_EXPORTED
 */
fun ComponentActivity.registerReceiverWithLifecycle(
    ownerProducer: () -> LifecycleOwner = { this },
    state: Lifecycle.State,
    receiverProducer: () -> BroadcastReceiver,
    intentFilter: IntentFilter,
    @ContextCompat.RegisterReceiverFlags flags: Int
) {
    val owner = ownerProducer()
    owner.lifecycleScope.launch {
        owner.repeatOnLifecycle(state) {
            val receiver = receiverProducer()
            ActivityCompat.registerReceiver(
                this@registerReceiverWithLifecycle, receiver, intentFilter, flags
            )
            try {
                awaitCancellation()
            } finally {
                unregisterReceiver(receiver)
            }
        }
    }
}