내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2020-07-09 08:07

제목

[Android] 안드로이드에서 반복 작업 수행(feat. 배터리 최적화 예외)


안드로이드 버전이 올라갈 수록 백그라운드 반복 작업에 제약이 강화되고 있습니다.

하지만 어떤 서비스들은 백그라운드 반복 작업이 필요한 경우도 있습니다. 이러한 서비스를 위하여 안드로이드에서는 배터리 최적화 예외 권한을 부여하고 있으며, 해당 권한을 이용하여 제약을 덜 받는 백그라운드 서비스를 개발할 수 있습니다.

이번 포스팅에서는 배터리 최적화 예외 설정이 된 상태에서 최적의 백그라운드 반복 작업을 구현하는 방법에 대하여 다뤄보도록 하겠습니다.

현재 안드로이드에서 백그라운드 반복 작업을 구현하고자 한다면 다음의 두가지 방법을 고려할 것입니다.

  • AlarmManager ( 모든 버전에서 사용 가능)
  • JobScheduler (API Level 21 이후 사용 가능)

AlarmManager의 경우 반복 작업을 실행하는 메소드가 API Level 마다 차이가 있습니다.

그렇다면 API Level이 21 보다 작은 경우에는 AlarmManager를 사용하고 21 이후에는 Scheduler를 사용하면 될까요?

테스트를 한번 해보도록 하겠습니다.

테스트는 다음과 같이 진행합니다.

  1. 앱 실행 시 배터리 최적화 예외 권한 확인 및 요청
  2. 10분을 주기로 AlarmManger를 이용하여 반복 작업 호출
  3. 10분을 주기로 JobScheduler를 이용하여 반복 작업 호출
  4. 각각 호출된 결과 체크 및 비교

배터리 최적화 예외

Manifest 파일에 퍼미션 추가

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

배터리 최적화 예외 검사

1
2
3
4
5
6
7
8
static boolean isIgnoringBatteryOptimizations(Context context) {
PowerManager powerManager =
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
}
return true;
}

배터리 최적화 예외 권한 요청

1
2
3
4
5
if(!Utils.isIgnoringBatteryOptimizations(this)) {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}

AlarmManager를 이용한 방법

AlarmManager + BroadcastReceiver를 이용하여 구현합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

Intent schedule = new Intent(REPEAT_START);
schedule.setClass(context, MyReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, schedule, 0);

Calendar interval = Calendar.getInstance();
interval.setTimeInMillis(System.currentTimeMillis());
interval.add(Calendar.MINUTE, Utils.INTERVAL_MINUTE);

if(Build.VERSION.SDK_INT >= 23) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
interval.getTimeInMillis(), sender);
} else if(Build.VERSION.SDK_INT >= 19){
alarmManager.setExact(AlarmManager.RTC_WAKEUP,interval.getTimeInMillis(), sender);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, interval.getTimeInMillis(), sender);
}

JobScheduler를 이용한 방법

JobScheduler 등록

1
2
3
4
5
6
7
8
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.cancelAll();
scheduler.schedule(new JobInfo.Builder(Utils.JOB_ID,
new ComponentName(this, MyJobService.class))
.setPeriodic(Utils.INTERVAL_MINUTE * 60 * 1000)
.build());
}

테스트 결과

테스트는 Galaxy S9+ / Android P 로 진행하였습니다. 테스트 단말기는 제가 실사용 하는 단말기이며 최대한 실사용 환경과 동일한 환경을 구성하려고 노력하였습니다.

테스트 주기는 10분이며, 수행 결과를 1시간 간격으로 표시하였습니다.

테스트 결과는 아래의 표와 같습니다.

test_result_1

테스트 결과 중 특정 하루를 비교한 결과입니다. 테스트 결과 AlarmManager는 일정하게 호출되었으며, JobScheduler는 불규칙적으로 호출되었고 실제 입력된 시간을 확인해보면 주기를 10분으로 설정하였음에도 10분 이내에 중복 호출되는 경우도 존재하였습니다.

실제 테스트는 약 한달동안 진행하였으며 대부분의 테스트 결과가 위의 표와 비슷하였습니다. 테스트 기간 중 특이사항은 배터리 최적화 예외 권한을 제거 하여도 위와 비슷한 결과가 나타났다는 것인데 이는 시스템에서 특정 조건에 만족하는 경우 백그라운드 제약을 하는데 그 특정조건에 부합하지 않아 일시적으로 발생한 경과라고 추정하였습니다.

따라서, 배터리 최적화 예외 권한을 요청하는 경우에는 AlarmManager가 더 정확하다고 판단되며, 필요에 따라 JobScheduler를 추가로 사용하는 것이 좋을 것 같습니다.

서비스의 필요에 따라 백그라운드 반복 작업이 반드시 필요한 경우도 분명 있습니다. 하지만 백그라운드 반복 작업은 단말기에 안좋은 영향을 끼칠 수 있으며 구글에서 백그라운드 반복 작업에 대한 제약은 앞으로도 계속 강화될 것으로 전망하기 때문에 백그라운드 반복 작업이 정말 필요한지 아니면 다른 방법으로 서비스를 제공할 수는 없는지에 대하여 신중히 고민해야 할 것 입니다.

출처1

https://wooyeol.github.io/2019/03/19/Android-Repeat-Background-Service

출처2