매니페스트 파일에 정적으로 등록된 브로드캐스트 리시버를, 인텐트 필터 정보를 이용해 암시적 인텐트로 실행시키려고 하면 에러가 발생한다.
Background execution not allowed: receiving Intent { act=ACTION_RECEIVER flg=0x10 } to com.example.test
외부 앱
에서는 클래스명 정보를 이용한 명시적 인텐트를 사용할 수 없기 때문에, 암시적 인텐트
로 브로드캐스트 리시버를 실행시킬 수밖에 없다. 내부 앱
에서는 브로드캐스트 리시버를 명시적 인텐트
로 실행시키면 되기 때문에, 백그라운드 제약 문제로 입는 피해는 없다. 동적 등록
한 경우에도 암시적 인텐트
로 리시버를 실행시킬 수 있다. 즉, 매니페스트 파일에 정적으로 등록된 브로드캐스트 리시버를 같은 어플리케이션 내에서 암시적 인텐트로 실행시키는 것만 금지되었다고 보면 된다.
백그라운드 상태
에 있을 때, 서비스를 실행시키기 위해서 인텐트를 발생시키면 에러가 발생한다. (명시적, 암시적 인텐트 모두) 포그라운드 상태
에 있다면 정상적으로 실행된다. Not allowed to start service Intent { act=ACTION_OUTER_SERVICE pkg=com.example.test }: app is in background uid null
포그라운드 상태란?
앱이 백그라운드 상태라고 하더라도, 아래의 경우에는 서비스가 정상적으로 실행된다.
백그라운드 상태에서 서비스가 정상적으로 실행되게 하려면?
→ startForegroundService() 함수로 인텐트를 발생시키면 서비스가 정상적으로 실행되긴 하지만, 얼마 지나지 않아 다음과 같은 에러가 발생한다.
Context.startForegroundService() did not then call Service.startForeground()
결국 startForegroundService()에 의해 실행된 서비스는 빠른 시간 내에 startForeground() 함수를 호출하여 포그라운드 상태로 바꿔줘야 한다. 이때 startForeground() 함수의 매개변수는 Notification 객체여서 상태바에 알림이 뜨게 된다.
개발자가 매니페스트 파일에 서비스를 등록시킬 때,android.permission.BIND_JOB_SERVICE
퍼미션이 설정되어 있어야 한다.
실행되는 조건을 JobInfo 객체에 담아서 시스템에 등록한다.
JobInfo.Builder(1, ComponentName(this, MyService::class.java)).run {
setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
jobScheduler?.schedule(build())
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tutorial.c79">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AndroidLab">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"></service>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
package com.tutorial.c79
import android.app.job.JobParameters
import android.app.job.JobService
import android.util.Log
class MyService : JobService() {
override fun onCreate() {
super.onCreate()
Log.d("haeun", "MyService... onCreate...")
}
override fun onDestroy() {
super.onDestroy()
Log.d("haeun", "MyService... Destroy...")
}
override fun onStartJob(p0: JobParameters?): Boolean {
Log.d("haeun", "MyService... onStartJob...")
return false // Job이 종료되었으므로 onStopJob은 호출되지 않음.
}
override fun onStopJob(p0: JobParameters?): Boolean {
Log.d("haeun", "MyService... onStartJob...")
return false
}
}
package com.tutorial.c79
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
val scheduler = getSystemService(JOB_SCHEDULER_SERVICE) as JobScheduler
JobInfo.Builder(1, ComponentName(this, MyService::class.java)).run {
setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 와이파이
scheduler.schedule(build())
}
}
}
}
와이파이에 연결된 경우에만 MyService 함수들의 로그가 출력된다.