일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- ec2 scp 파일 전송
- spring 동적 쿼리 주의사항
- 운영체제 커널모드
- 운영체제 자원관리
- spring responseEntity response cause
- android 타이머
- 백엔드 직무 변경
- Android Timer
- 운영체제 멀티 프로그래밍
- aws ec2 scp 파일 전송
- 운영체제 멀티 태스킹
- spring responseEntity response stackTrace
- spring sql injection
- 운영체제 다중모드
- 개발 포지션 변경
- 백엔드 포지션 변경
- spring exception cause remove
- 운영체제 작동방식
- IT 직무 변경
- spring dynamic query sql injection
- OS 자원관리
- spring paging sort sql injection
- spring exceptionHandler response cause
- 운영체제 개념
- spring exceptionHandler reposnse stackTrace
- 개발 직무 변경
- 운영체제 공룡책
- spring sql injection 방지
- IT 포지션 변경
- spring exception stackTrace remove
- Today
- Total
오늘도 삽질중
android Oreo 이상 앱 종료시점 본문
Android Oreo 이상 앱 종료시점 캐치하기
해당 블로그는 다음과 같은 분들에게 도움이 될꺼라 판단합니다.
앱 종료시점(슬라이드 종료) 를 캐치하는데 Oreo 이상은 startForegroundService를 실행하는건 알고 있다.
문제는 startForegroundService 는 노티피케이션 ui가 생기는데 이걸 제거하고 싶다.
또는
간단한 백그라운드 서비스를 구현하려고 할 때
startForegroundService를 사용하여 편법으로 백그라운드에서 서비스를 돌릴수 있을까?
아마 이 블로그를 들어온 사람들은 거의 비슷하게 생긴 예제들을 봤을거라고 생각합니다.
서비스 시작시 OS 버전을 체크하여 서비스를 실행한다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, TerminateService::class.java))
} else {
startService(Intent(this, TerminateService::class.java))
}
하지만 저처럼 위와 같은 문제로 고민하시는 분들이 있을꺼 같아 여러 블로그를 찾아보고 간단하면서 원하는 방식으로
해결할 수 있었습니다.
https://vision-ary.tistory.com/16
해당블로그의 도움을 받았습니다. 한번 읽어보시면 좋을 거 같습니다.
위와 같은 문제를 해결한 방법의 핵심은
Oreo 미만은 기존 그대로 startService를 호출하지만
Oreo 이상 버전은 startForegroundService를 호출하고 그 안에서 startService를 실행한다 입니다.
바로 코드로 넘어가겠습니다.
class TerminateService : Service() {
override fun onCreate() {
super.onCreate()
}
override fun onDestroy() {
super.onDestroy()
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onTaskRemoved(rootIntent: Intent) {
/**
* 해당 부분에서 앱 종료시점을 캐치할 수 있다.
*/
stopSelf()
}
override fun onLowMemory() {
super.onLowMemory()
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
}
기본적인 Service()를 상속받은 Class입니다. 실제 동작해야 될 코드가 기술되어 있을겁니다.
그 다음 하나의 Service()를 상속받은 또 다른 Class를 작성합니다.
/**
* 오레오 버전 이상 임시로 실행하는 서비스
* 해당 서비스 내에서 실제로 동작하는 서비스를 실행시킨다.
*/
class TerminateServiceOreo : Service() {
override fun onCreate() {
super.onCreate()
}
override fun onDestroy() {
super.onDestroy()
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onTaskRemoved(rootIntent: Intent) {
}
override fun onLowMemory() {
super.onLowMemory()
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("Background", "Service", NotificationManager.IMPORTANCE_LOW)
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
val notification = NotificationCompat.Builder(this, channel.id).build()
startForeground(1, notification)
val realService = Intent(this , TerminateService::class.java)
startService(realService)
stopForeground(true)
stopSelf()
}
return START_NOT_STICKY
}
}
Oreo 이상에서 실행시킬 서비스입니다.
START_NOT_STICKY로 서비스가 종료되어도 다시 실행하지 않으며,
stopForeground(true) 로 노티피케이션 ui를 제거합니다.
그 다음 실제로 구현에 필요한 서비스를 startService로 실행합니다.
이제 해당 서비스를 버전별로 다르게 실행합니다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, TerminateServiceOreo::class.java))
} else {
startService(Intent(this, TerminateService::class.java))
}
Oreo 이상은 TerminateServiceOreo 를 실행하고,
그 미만버전은 TerminateService를 실행합니다.
마지막으로 메니페스트에 서비스를 추가해줍니다.
<service android:name=".service.TerminateService" android:stopWithTask="false"/>
<service android:name=".service.TerminateServiceOreo" android:stopWithTask="true"/>
참고로 Java에서 kotlin으로 변환하게 되면 아래처럼 onStartCommand로 변환됩니다.
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return START_STICKY
}
이렇게 그대로 쓰시게 되면....
Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter intent
에러를 보게 됩니다. 그러므로 꼭 Intent 옆에 ? 를 붙여서 사용해주세요.
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
'안드로이드' 카테고리의 다른 글
Android 특정 이미지만 trying to use a recycled bitmap 에러가 발생한다면? (0) | 2021.01.21 |
---|---|
Android Rxbinding 과 combineLatest 를 사용해보자 (0) | 2021.01.20 |
Android SAF 파일,폴더 생성 예제 with. DocumentFile (0) | 2020.12.10 |
Android retrofit Rxjava httpCode 확장함수로 편하게 처리하기 (0) | 2020.11.05 |
Android 디자인패턴이 그렇게 중요할까? (0) | 2020.06.30 |