일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- hilt
- sqlite
- CustomView
- Behavior
- Algorithm
- lifecycle
- DataBinding
- View
- CollapsingToolbarLayout
- room
- 코틀린
- notification
- CoordinatorLayout
- 안드로이드
- recyclerview
- kotlin
- 알고리즘
- Navigation
- 알림
- BOJ
- onMeasure
- Coroutine
- onLayout
- Android
- activity
- ViewModel
- HTTP
- LiveData
- AppBarLayout
- 백준
- Today
- Total
개발일지
Android in A..Z - Service 본문
Service
어플리케이션이 종료되도 작업을 유지할 수 있는 요소(Android 4대 Component 중 하나이다.)이다. 크게 Background와 Foreground, Bind로 나눌 수 있습니다. Background는 UI가 제공되지 않고 Foreground는 Notification으로 UI가 제공되며 Bind는 Binder로 Service와 통신할 수 있습니다.
* Oreo 이상에서 베터리에 대한 규제가 강화되면서 Background Service를 사용하기 어렵습니다.
https://developer.android.com/about/versions/oreo/background?hl=ko#services
-> 앱 종료시 Background 종료됩니다.
* Service를 생성해도 내부적으로 새로운 Thread를 만드는 것은 아닙니다. Service에서 무거운 작업을 진행한다면 내부에서 새로운 Thread를 만들어야 합니다.
* Android Developer에서는 Action으로 Service를 실행하는 방법을 추천하지 않습니다. 그 이유는 원치않는 Service가 호출되어 Resource를 낭비할 수 있기 때문입니다.
-> Class로 명시적으로 실행하면 됩니다.
onCreate
서비스가 처음 생성될 때 수행된다. 초기화 작업을 진행하면 된다.
* 서비스가 이미 진행중일 때 startService를 호출하면 onCreate는 호출되지 않습니다.
onBind
bindService로 호출할 때 진행됩니다. IBinder를 반환하여 Service를 호출한 컴포넌트와 통신할 수 있습니다.
* bindService를 사용하지 않는 경우 null을 반환하면 됩니다. onBind를 호출한 컴포넌트가 종료되면 서비스도 같이 종료됩니다.
onStartCommand
실제 작업이 이루어지는 공간입니다. startService를 호출하면 진행하며, Service가 만들어진 상태에서는 onCreate가 호출되지 않고, onStartCommand가 바로 호출됩니다.
반환값에 따라 Service가 종료 후 재실행 될 때 상태를 정합니다. (Android에서 리소스가 부족하면 Service를 종료시키고 리소스가 확보될 때 다시 실행시키는 경우가 있다.)
- START_NOT_STICKY : 전달해야 하는 Intent가 없는 경우 서비스를 재생성하지 않습니다. (불필요한 서비스 재생성을 막을 수 있습니다.)
- START_STICKY : Intent를 null로 지정하여 서비스를 재생성합니다.
- START_REDELIVER_INTENT : 마지막으로 전달받은 Intent를 통해 재실행 합니다.
onDestroy
서비스가 끝날 때 호출됩니다. Thread 종료 등 자원을 반납하는 코드를 작성합니다.
stopSelf
서비스가 생성되면 생명주기는 개발자가 직접 관리해야 합니다. 작업이 종료되면 stopSelf를 통해 서비스를 종료 시킬 수 있습니다.
Git (예제코드)
https://github.com/KangTaeJong98/Example/tree/main/Android/AndroidComponent
GitHub - KangTaeJong98/Example: My Example Code
My Example Code. Contribute to KangTaeJong98/Example development by creating an account on GitHub.
github.com
open class ScreenStateService : Service() {
private var screenStateReceiver: ScreenStateReceiver? = null
override fun onCreate() {
super.onCreate()
CoroutineScope(Dispatchers.Main).launch {
while (true) {
delay(1500L)
Toast.makeText(this@ScreenStateService, "Running", Toast.LENGTH_SHORT).show()
Log.d("PASS", "Running")
}
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
ScreenStateReceiver().also { receiver ->
screenStateReceiver = receiver
registerReceiver(receiver, IntentFilter(Intent.ACTION_SCREEN_ON))
}
return START_REDELIVER_INTENT
}
override fun onDestroy() {
super.onDestroy()
screenStateReceiver?.let { receiver ->
screenStateReceiver = null
unregisterReceiver(receiver)
}
}
}
class MyBindService : Service() {
private var value = 0
override fun onCreate() {
super.onCreate()
CoroutineScope(Dispatchers.IO).launch {
while (true) {
delay(1500L)
value++
}
}
}
override fun onBind(intent: Intent): IBinder {
return object : Binder(), MyBindInterface {
override fun getValue(): Int {
return value
}
}
}
private interface MyBindInterface {
fun getValue(): Int
}
open class MyBindConnection : ServiceConnection {
private var binder: MyBindInterface? = null
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
if (binder is MyBindInterface) {
this.binder = binder
}
}
override fun onServiceDisconnected(name: ComponentName) {
}
fun getValue(): Int {
return binder!!.getValue()
}
}
}
class MainActivity : AppCompatActivity() {
private val binding: ActivityMainBinding by lazy { DataBindingUtil.setContentView(this, R.layout.activity_main) }
private var connection: MyBindService.MyBindConnection? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.lifecycleOwner = this
binding.setOnBind {
if (connection == null) {
val conn = object : MyBindService.MyBindConnection() {
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
super.onServiceConnected(name, binder)
connection = this
Toast.makeText(this@MainActivity, getValue().toString(), Toast.LENGTH_SHORT).show()
}
override fun onServiceDisconnected(name: ComponentName) {
super.onServiceDisconnected(name)
connection = null
}
}
bindService(Intent(this, MyBindService::class.java), conn, BIND_AUTO_CREATE)
} else {
Toast.makeText(this, connection!!.getValue().toString(), Toast.LENGTH_SHORT).show()
}
}
binding.setOnOff {
connection?.let { unbindService(it) }
stopService(Intent(this, MyBackgroundService::class.java))
stopService(Intent(this, MyForegroundService::class.java))
}
binding.setOnBackground {
startService(Intent(this, MyBackgroundService::class.java))
stopService(Intent(this, MyForegroundService::class.java))
}
binding.setOnForeground {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, MyForegroundService::class.java))
} else {
startService(Intent(this, MyForegroundService::class.java))
}
stopService(Intent(this, MyBackgroundService::class.java))
}
}
override fun onStart() {
super.onStart()
val manager = getSystemService(PowerManager::class.java)
if (!manager.isIgnoringBatteryOptimizations(packageName)) {
AlertDialog.Builder(this)
.setTitle("Request Permission")
.setMessage("We need permission to running app")
.setCancelable(false)
.setPositiveButton("OK") { _, _ ->
Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS).also {
startActivity(it)
}
}
.show()
}
}
}
'Android (안드로이드)' 카테고리의 다른 글
Android in A..Z - Manifest (0) | 2021.10.12 |
---|---|
Android in A..Z - Broadcast Receiver (0) | 2021.10.07 |
Android in A..Z - Fragment (0) | 2021.10.04 |
Android in A..Z - Glide Advanced (0) | 2021.10.01 |
Android in A..Z - Span (0) | 2021.09.16 |