티스토리 뷰

AlarmManager의 필요성


개발을 진행하면서 백그라운드로 특정주기마다 특정서버와 데이터를 동기화 하는 기능을 수행해야 하는 경우가 있었습니다.
처음에는 Service에서 Thread를 돌리면서 sleep을 주어 특정주기마다 돌면서 하는 방향으로 진행 하면 되는 것으로 생각 했지만 실제로 테스트 구동을 해보니 문제가 발견 되었습니다. 서비스에서 thread는 돌고 있지만 돌면서 주기가 일정하지 않고 지속적으로 delay 현상이 발생되고 있었던 것입니다.
폰의 대기모드등 doz상태에 빠지게 되는 경우 OS에서 배터리 손실을 방지 하기 위해서 최소한의 동작을 제외한 백그라운드 작업들은 특정주기마다 모아서 처리 하기 때문에서비스에서 돌고 있던 Thread의 delay가 발생 되고 있었던 것이었습니다. 해당 delay를 해결 하기 위해서 사용 한것이 바로 AlarmManager입니다.

AlarmManager는 반복적인 스케쥴링을 구현할때 사용하는 것으로 이 AlarmManager을 이용하면 doz상태일때도 정상적으로 설정된 주기마다 이벤트가 발생 됩니다.



AlarmManager의 사용법


AlarmManager는 API버전별로 코드를 분기처리해야 정상적으로 동작 하게 되는데, 여기에서는 매10초마다 특정 이벤트를 실행해야 하는 경우를 가정하고 설명하도록 하겠습니다.
또한 AlarmManager는 자동으로 반복되지 않으므로 알림이 발생된 후 다시 알람을 등록하는식으로 반복 처리 되도록 하겠습니다.
API 19(KITKAT 4.4)미만의 경우에는 AlarmManager의 set()를 사용 하면 됩니다. 
API 19(KITKAT 4.4)이상부터 API 23(Marshmallow 6.0)미만까지는 setExact()를 사용해야 정확한 알람을 받을 수있습니다.
API 23(Marshmallow 6.0)이상부터는 doz모드가 추가되어 기존 사용법으로 정상적으로 작동하지 않으며, setExactAndAllowWhileIdle()를 사용해야 정확한 알람을 받을 수 있게 됩니다.
현재 글을 작성되는 시점에서는 API 26(8.0)까지 나와 있습니다. 이후 추가적으로 API가 출시되면 또 AlarmManager의 사용해야 할 Method가 달라질 수 있습니다.
각각의 API레벨별로 분기해서 코드를 작성 해주어야 합니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 public void testAlarm(){
         Intent intent = new Intent("AlarmService");
           PendingIntent sender = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);
           long firstTime = SystemClock.elapsedRealtime();
           firstTime += 10*1000//10초 후 알람 이벤트 발생                                              
           AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);          
           if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M){  
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 
               //API 19 이상 API 23미만 
               am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, sender) ;
            } else { 
              //API 19미만
                am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, sender);             
            }
        } else {       
          //API 23 이상
         am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, sender);
        }
      }
cs

위 소스는 API로 분기처리 해 각각의 AlarmManager를 등록하는 내용입니다.



Reciever 등록

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BroadcastReceiver testReceiver;
     @Override
    public void onCreate() {
     // TODO Auto-generated method stub
     super.onCreate();
     testReceiver = new BroadcastReceiver(){
   @Override
   public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub    
    // 이벤트 처리 
     
    //AlarmManager 재 등록
    testAlarm();
   }   
  };
  registerReceiver(testReceiver, new IntentFilter("AlarmService"));
}
cs


AlarmManager에 의해 실해되면 "AlarmService"라는 이름의 Broadcast를 발생하게 하였고 

이를 Reciever에서 받아서 이벤트를 처리 후 다시 AlarmManager를 등록하여 반복적으로 처리 되도록 하였습니다.
이와 같이 처리하여 서비스에서 동작 하였더니 정상적으로 원하는 주기마다 AlarmManager가 실행되었습니다. 

댓글