노블의 개발이야기

[안드로이드 개발 레벨업 교과서] 3.2 BroadcastReceiver로 브로드캐스트 이벤트를 수신하자 본문

Books

[안드로이드 개발 레벨업 교과서] 3.2 BroadcastReceiver로 브로드캐스트 이벤트를 수신하자

더플러스 2017. 7. 26. 11:27

어떤 이벤트가 발생한 사실을 앱에 알리고 싶을 때 BroadcastReceiver에 통지한다.

단말기 전원이 들어왔거나 디스크 용량 부족 등 시스템의 이벤트를 앱에 알리거나, 앱간의 연계를 위해 이벤트를 알리고 싶을 때 이용한다.

3.2.1 BroadcastReceiver의 기본을 이해하자

BroadcastReceiver는 브로드캐스트 Intent를 받았을 때의 처리를 onReceive에서 구현한다.

어느 브로드 캐스트 Intent를 받을 지는 IntentFilter로 정의한다.

public abstract void onReceive(Context context, Intent intent);

두 번째 인수로 전달되는 Intent는 Context.sendBroadcast() 등에서 보내진 블로드캐스트 Intent의 인스턴스이다.

Note: onReceive()의 처리는 메인 스레드에서 수행되므로 처리에 시간이 걸려서는 안된다. 처리에 10초 이상 걸리는 경우 ANR이 발생해 프로세스가 강제로 종료된다.

BroadcastReceiver 등록

1. AndroidManifest.xml에 receiver 태그를 이용한 등록

<receiver android:name=".BootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

BOOT_COMPLETED의 브로드캐스트를 받으려면 RECEIVE_BOOT_COMPLETED 퍼미션이 필요합니다.

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

2. Context.registerReceiver를 이용한 등록

public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";

BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        intent.getExtras();
        if (TextUtils.equals(action, VOLUME_CHANGED_ACTION)) {
            Toast.makeText(MainActivity.this, "음량이 변화했습니다", Toast.LENGTH_SHORT).show();
        }
    }
};

...

@Override
protected void onResume() {
    super.onResume();

    IntentFilter filter = new IntentFilter(VOLUME_CHANGED_ACTION);
    registerReceiver(mReceiver, filter);
}

@Override
protected void onPause() {
    super.onPause();

    unregisterReceiver(mReceiver);
}

3.2.2 LocalBroadcastReceiver를 이해하자

브로드캐스트는 다른 앱에 송신하는 것이 가능하지만 경우에 따라서는 다른 앱에 알릴 필요 없이 앱 내에서 완결시키고 싶을 때 로컬 브로드캐스트를 이용합니다.

LocalBroadcastReceiver의 장점

  • 다른 앱에 통지하지 않아 보안 향상
  • 프로세스 간 통신을 하지 않아 성능 향상

로컬 브로드캐스트는 Service와 조합해 이용하는 경우가 많다.

Service 쪽에서 처리하고, 처리가 끝나면 액티비티나 프래그먼트에 로컬브로드캐스트해 처리 완료를 알리는 식으로 사용한다.

3.2.3 브로드캐스트를 수신해 처리할 때 주의할 점

안드로이드는 전력 소비를 줄이고자 사용자 화면을 끄면 슬립 상태로 들어갑니다.

브로드캐스트를 수신해서 뭔가 시간이 오래 걸리는 처리를 한창 하는 중에 슬립되는 경우가 있습니다.

단말기 상태

슬립 상태에서도 처리를 계속하려면 CPU를 깨울 필요가 있다.

이런 동작을 안드로이드 시스템에서는 WakeLock을 얻는다고 한다.

  • WakeLock의 종류와 단말기 상태 변화
화면 상태 CPU 상태 대응하는 WakeLock
화면 ON(밝다) CPU ON FULL_WAKE_LOCK
화면 ON(약간 어둡다) CPU ON SCREEN_DIM_WAKE_LOCK
화면 OFF CPU ON PARTIAL_WAKE_LOCK
화면 OFF CPU OFF 없음

Note: FULL_WAKE_LOCK, SCREEN_DIM_WAKE_LOCK은 현재 Deprecated 예정 상태이므로 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON 을 대신 사용하기를 권장한다.

WakeLock 해제를 잊으면 CPU가 슬립할 수 없어 계속 동작한다.

다행히 지원 라이브러리에 WakefulBroadcastReceiver라는 클래스가 있어서 이 클래스를 이용하면 처리 중에만 WakeLock을 얻고 처리가 끝나면 해제하는 일련의 흐름을 실행해 준다.

WakefulBroadcastReceiver로 얻은 WakeLock은 60초로 타임아웃이 설정되어 있다. 처리 시간이 60초 이상 걸리면 슬립상태로 전환된다.

WakeLock을 사용하려면 WAKE_LOCK 퍼미션이 필요하다.

<uses-permission android:name="android.permission.WAKE_LOCK"/>

WakefulBroadcastReceiver.onRecieve()에서 startWakefulService()를 호출해 WakeLock을 얻은 상태에서 IntentService를 시작하고 그 안에서 처리한다.

public class MyReceiver extends WakefulBroadcastReceiver {
    public MyReceiver() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("MyReceiver", "onReceive");
        Intent serviceIntent = new Intent(context, MyIntentService.class);
        startWakefulService(context, serviceIntent);
    }
}

IntentService 에서 처리가 끝나면 WakefulBroadcastReceiver.completeWakefulIntent()를 호출해 WakeLock을 해제한다.

IntentService는 백그라운드 스레드에서 처리하며 처리가 끝나면 자기 자신을 완료하는 편리한 클래스 이다.

public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            // 처리할 내용
            
        } finally {
            WakefulBroadcastReceiver.completeWakefulIntent(intent);
        }
    }
}

WakeLock 상태 확인

adb를 통해 WakeLock의 상태를 확인할 수 있다.

adb shell dumpsys power



Notice: 이 글은 [안드로이드 개발 레벨업 교과서]를 스터디하면서 정리한 내용입니다.

Comments