안드로이드 18) Background Limit

밍나·2022년 1월 29일
0

Android

목록 보기
18/36

Concepts of Background Limit

1. Background Limit

  • 안드로이드 앱은 액티비티, 서비스, 브로드캐스트 리시버, 컨텐츠 프로바이더로 구성되어 있고 액티비티를 제외한 나머지는 화면과 상관없는 백그라운드 작업을 목적
  • 백그라운드 제약은 안드로이드 8버전(API Level 26버전)부터 앱의 화면이 출력되지 않은 상황에서 백그라운드 업무를 처리하는 것에 제약이 가해진 것이다.
    • 정확히 말하자면, 시스템이 부팅 완료되자마자 브로드캐스트 리시버를 실행시키고 이를 이용하여 서비스를 실행시켜 어떤 업무(백그라운드 업무)를 처리하는 것이 불가능해졌다는 것이다.

Broadcast Limit

  • 브로드캐스트 리시버에는 제약이 가해지긴 했지만 다른 방법으로 얼마든지 실행시킬 수 있기 때문에 문제가 발생하지는 않을 것이다.

1. Broadcast Limit

<receiver
    android:name=".MyReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
    	<action android:name="ACTION_RECEIVER"/>
    </intent-filter>
</receiver>
val intent = Intent("ACTION_RECEIVER")
sendBroadcast(intent)
  • 브로드캐스트 리시버를 실행시키기 위해서는 인텐트를 sendBroadcast() 함수로 발생시킨다.
  • 브로드캐스트 리시버를 암시적 인텐트에 의해 실행시키는 것 금지되었다.

  • 그럼 위의 코드는 실행이 안되냐?
  • 위의 그림과 같이 같은 앱에서 액티비티가 암시적 인텐트로 실행시키는 것은 안되지만, 다른 앱에서 액티비티가 암시적 인텐트로 실행시키는 것은 가능하다.
  • 즉 내부에서 브로드캐스트 리시버를 암시적 인텐트로 실행시키는 것이 금지된 것이다.
    • 내부에서는 브로드캐스트 리시버를 실행시키려면 명시적 인텐트로 실행시켜야 한다.
receiver = object: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
    	Log.d("broadcast limit", "outer app dynamic receiver")
    }
}

registerReceiver(receiver, IntentFilter("ACTION_OUTER_DYNAMIC_RECEIVER"))
  • 하지만 코드에서 regosterReceiver()로 등록시킨 경우는?
  • 이 경우에는 암시적 인텐트로 실행이 가능하다.

2. Broadcast Limit 정리

Service Limit

1. Service Limit

  • 앱이 백그라운드 상태에 있을 때 서비스를 실행시키기 위해서 명시적 혹은 암시적 인텐트를 발생시키면 에러 발생
  • Service Limit이 발생하지 않는 경우
    • 앱이 포그라운드 상황이라면 정상 실행
      • 우리 앱의 Activity가 화면에 출력되는 경우
      • 우리 앱의 여러 서비스 중 하나가 포그라운드 서비스로 동작하는 경우
      • 우리 앱의 서비스 중 하나가 다른 앱의 bind되어 다른 앱이 포그라운드로 실행하는 경우
      • 우리 앱의 콘텐츠 프로바이더 중 하나를 포그라운드로 실행되는 다른 앱에서 사용하는 경우
    • 앱이 백그라운드 상황이어도 아래의 경우 정상 실행
      • 우선 순위가 높은 Firebase 클라우드 메시징(FCM) 메시지 처리
      • SMS/MMS 메시지와 같은 브로드캐스트 수신
      • 알림(notification)에서 PendingIntent 실행
      • VPN 앱이 포그라운드로 승격되기 전에 VpnService 시작

2. Service Limit 해결 방법

  • 백그라운드 상황에서 서비스가 정상 실행되게 할 수 있는 방법
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    startForegroundService(intent)
} else {
    startService(intent)
}
  • startForegroundService() 함수에 의해 인텐트를 발생시키면 앱의 백그라운드 상황이라고 하더라도 정상적으로 서비스가 실행
  • startForegroundService() 함수에 의해 서비스가 정상 실행되기는 하지만 얼마 후 에러가 발생
val notification = builder.build()
startForeground(1, notification)
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
  • startForegroundService()에 의해 실행된 서비스 내에서 빠른 시간내에 startForeground() 함수(매개변수 : 알림 객체)를 호출해줘서 notification을 띄워줘야 한다.
  • 유저 입장에서는 쓸데 없는 notification을 띄우는 것이 불편할 수 있음

JobScheduler

1. JobScheduler

  • JobScheduler을 이용하면 앱이 백그라운드 상황에서도 업무처리 가능
    • JobScheduler는 일종의 서비스
    • 하지만 인텐트로 실행시키지 않고 시스템에 등록을 하면 시스템에서 특정 상황이 됐을 때 실행
  • 조건을 명시하고 그 조건에 맞는 경우에만 백그라운드 업무 처리 가능
    • 네트워크 타입
    • 배터리 충전 상태
    • 특정 앱의 컨텐츠 프로바이더의 갱신
    • 실행 주기
    • 최소 지연 시간

2. JobScheduler 사용 방법
1) android.permission.BIND_JOB_SERVICE 퍼미션이 등록

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true"
    android:permission="android.permission.BIND_JOB_SERVICE"></service>

2) JobService 구현

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class MyService: JobService() {
    override fun onCreate() {
    	super.onCreate()
    }
    
    override fun onDestroy() {
    	super.onDestroy()
    }
    
    override fun onStartJob(params: JobParameters?): Boolean {
    	return false
    }
    
    override fun onStopJob(params: JobParameters?): Boolean {
    	return false
    }
  • onStartJob() : 백그라운드에서 처리되어야 하는 업무를 가지는 함수
    • 리턴값에 따라 다르게 동작
      • false : Job이 완벽하게 종료되었다는 의미 → onStopJob이 호출되지 않음
      • true : Job이 아직 끝나지 않았음을 의미
  • onStopJob()
    • 리턴값에 따라 다르게 동작
      • false : JobScheduler 등록이 취소, 조건을 만족해도 다시 실행되지 않음
      • true : 다시 JobScheduler 등록, 조건을 만족하면 다시 실행될 수 있음

3) 실행되는 조건을 JobInfo 객체에 담아 시스템에 등록

JobInfo.Builder(1, ComponentName(this, MyService::class.java)).run {
    setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
    jobScheduler?.schedule(build())
}
  • 어떤 JobService를 실행할 건지를 지정해주고 몇몇 setter 함수로 조건을 준다.
  • setter 함수 종류
    • setPersisted(true) : 단말을 재부팅해도 Job 등록 유지해야 하는지 설정
    • setPeriodic(long intervalMillis) : Job의 실행 주기 설정
    • setMinimumLatency(long minLatencyMillis) : Job 실행의 지연 시간 설정
    • setOverrideDeadline(long maxExecutionDelayMillis) : 다른 조건이 만족하지 않는다고 하더라도 이 시간 안에 Job이 실행되어야 함을 설정
    • setRequiredNetworkType(int networkType) : 네트워크 타입 설정
    • setRequiresBatteryNotLow(boolean batteryNotLow) : 배터리가 낮은 상태가 아님을 설정
    • setRequiresCharging(boolean requiresCharging) : 배터리가 충전 상태인지를 설정
profile
🤗🤗🤗

0개의 댓글