μλ νμΈμ
μ€λμ μλλ‘μ΄λμ Serviceμ λνμ¬ κ³΅λΆν λ΄μ©μ
ν¬μ€ν ν΄λ³΄λ € ν©λλ€.

Service(μλΉμ€)λ?
μΌμ ν κ°κ²©μΌλ‘ λ°±κ·ΈλΌμ΄λμμ μ€νλλ νλ‘μΈμ€ μ¦, νλ©΄μμλ 보μ΄μ§ μμ§λ§
λ€μμ μ§μμ μΌλ‘ ν΄μΌ νλ μμ μ μν΄μ μ¬μ©νλ μ»΄ν¬λνΈμ λλ€.
βοΈ μλΉμ€λ λ‘컬μμ μνλλ μλΉμ€( startService( ) )μ μ격μμ μ€νλλ μλΉμ€( bindService( ) )κ° μ‘΄μ¬
Service(μλΉμ€)μ μλͺ μ£ΌκΈ°

μ μ΄λ―Έμ§λ μλΉμ€μ μλͺ μ£ΌκΈ°λ₯Ό λνλλ μ΄λ―Έμ§μ λλ€.
μλΉμ€λ Activityμ λ§μ°¬κ°μ§λ‘ μλͺ μ£ΌκΈ°κ° μ‘΄μ¬νλ©° λ‘컬 μλΉμ€μ μ격 μλΉμ€μ μλͺ μ£ΌκΈ°λ μλ‘ λ€λ₯Έ κ²μ λ³Ό μ μμ΅λλ€.
Localμμ λμνλ μλΉμ€μ κ²½μ°
startService()λ‘ μλΉμ€λ₯Ό μμνλ κ²½μ°
onCreate() -> onStartCommnad() -> μλΉμ€ stop -> onDestroy()λ‘ λμνλ©°
μ΄λ―Έ μλΉμ€κ° μ€ν μ€μΈ κ²½μ°μλ onCreate()λ₯Ό μ€ννμ§ μκ³ λ°λ‘ onStartCommnad()λ₯Ό νΈμΆν©λλ€.
Remote( μ격 )μμ λμνλ μλΉμ€μ κ²½μ°
bindService()λ₯Ό νΈμΆνλ κ²½μ°μλ
onCreate -> onBind() -> μλΉμ€ stop -> onUnbind() -> (μ°κ²°λμ΄ μλ νλ‘μΈμ€κ° μλ€λ©΄) onDestroy()
λ‘ λμνλ©° onStartCommand()λ νΈμΆνμ§ μμ΅λλ€.
ForegroundServiceλ?
λ°±κ·ΈλΌμ΄λμ μλΉμ€κ° μ¬μ©μμκ² ν΅μ§(Notification)νμ¬
μμ€ν
μ΄ μλΉμ€λ₯Ό μ€λ¨ν νλ³΄λ‘ κ³ λ €νμ§ μλ μλΉμ€(μ¬μ©μμκ² μλΉμ€λ₯Ό μ€μ§ν κ²μΈμ§ μ ν)
βοΈAndroid Oreo : 8λΆν°λ μ무μ μΌλ‘ ꡬνν΄μΌ νλ€.
startForegroundService()λ‘ μ€ν
λ§μ§λ§μΌλ‘ κ°λ¨ν μμ λ₯Ό 보면μ μλΉμ€μ μ¬μ©λ²μ μμλ³΄κ² μ΅λλ€. π
< activity_main.xml μ½λ >
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/startBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="μλΉμ€μμ"/>
<Button
android:id="@+id/stopBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/startBtn"
android:layout_centerHorizontal="true"
android:text="μλΉμ€μ’
λ£"/>
</RelativeLayout>
< MainActivity.kt μ½λ >
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.pyo.service.lifecycle.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
private lateinit var serviceIntent : Intent
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate()")
binding = ActivityMainBinding.inflate(layoutInflater).also {
setContentView(it.root)
}
serviceIntent = Intent(this@MainActivity , NewsService::class.java)
binding.run {
startBtn.setOnClickListener { executeButtonEvent(it) }
stopBtn.setOnClickListener { executeButtonEvent(it) }
}
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy()")
stopService(serviceIntent) // μ± μ’
λ£μμ μλΉμ€λ ν¨κ» μ’
λ£
}
private fun executeButtonEvent(view : View) { // Button μ΄λ²€νΈ μ€μ ν¨μ
when(view.id){
R.id.startBtn -> {
serviceIntent.putExtra("newSubhect" , 3)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
// Android 8μ΄μμμλ ForegroundServiceλ‘ μ€ν
startForegroundService(serviceIntent)
}
else {
startService(serviceIntent)
}
}
R.id.stopBtn -> {
stopService(serviceIntent)
}
else -> stopService(serviceIntent)
}
}
}
< NewsService.kt >
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationCompat
import kotlin.random.Random
const val CHANNEL_ID = "news_channel_id"
const val CHANNEL_NAME = "news_desk"
class NewsService : Service() {
private val TAG = "NewService"
private var extraValue = 0
private var mHandler = Handler(Looper.getMainLooper())
private lateinit var mSubThread : BackgroundSubThread
override fun onBind(p0: Intent?): IBinder? {
Log.d(TAG, "onBind() ")
return null
}
override fun onCreate() {
super.onCreate()
Log.d(TAG, "onCreate()")
Toast.makeText(applicationContext , "μλΉμ€λ₯Ό μμν©λλ€." , Toast.LENGTH_SHORT).show()
displayNotification()
mSubThread = BackgroundSubThread("subThread")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
Log.d(TAG, "onStartCommand()")
extraValue = intent!!.getIntExtra("newSubject" , 0)
if(!::mSubThread.isInitialized){
mSubThread = BackgroundSubThread("subThread")
}
if(!mSubThread.isAlive){
mSubThread.start()
}
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy()")
if(mSubThread.isAlive){
mSubThread.interrupt()
}
stopSelf()
}
inner class BackgroundSubThread(threadName : String) : Thread(threadName){
private val newsMap : java.util.HashMap<Int , String> = java.util.HashMap()
private val random : Random = Random(System.currentTimeMillis())
private var newsMessage : String? = null
init {
newsMap[0] = "first news"
newsMap[1] = "second news"
newsMap[2] = "third news"
newsMap[3] = "fourth news"
}
override fun run() {
super.run()
while (!isInterrupted){
newsMessage = newsMap[extraValue]
try {
mHandler.post {
Toast.makeText(applicationContext, newsMessage, Toast.LENGTH_SHORT).show()
}
extraValue = random.nextInt(4)
sleep(3000)
} catch (e : InterruptedException){
currentThread().interrupt()
}
}
}
}
private fun displayNotification() { // Status barμ μλΉμ€ μ€νμ€μ notify νκΈ° μν ν¨μ
val intent = Intent(this , MainActivity::class.java)
val pIntent = PendingIntent.getActivity(this , 1004 , intent , PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
val channel = NotificationChannel(CHANNEL_ID , CHANNEL_NAME , NotificationManager.IMPORTANCE_DEFAULT)
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
val builder = NotificationCompat.Builder(this , CHANNEL_ID)
builder.setSmallIcon(R.mipmap.ic_launcher_round).setContentTitle("NewService").setContentText("μλΉμ€κ° μ€νμ€μ
λλ€!").setContentIntent(pIntent)
startForeground(12345 , builder.build())
}
}
}
μ μμ λ NewsServiceλΌλ μλΉμ€λ₯Ό νλ μμ±νμ¬
μλΉμ€ λ΄λΆμμ SubThreadλ₯Ό ν΅ν΄ 3μ΄ κ°κ²©μΌλ‘ λ΄μ€λ₯Ό Toast νλ κ°λ¨ν μ±μ λλ€.
Android 8 μ΄μλΆν°λ ForegroundServiceλ‘ μ€ννμ¬μΌ νκΈ°μ
SDK λ²μ μ 체ν¬νμ¬ μλΉμ€ μ€ννλ ν¨μλ₯Ό λ€λ₯΄κ² νΈμΆνκ³ μμ΅λλ€.
MainActivityμμλ λ²νΌμ ν΅ν΄ μλΉμ€λ₯Ό μ€ν λ° μ’ λ£μν¬ μ μλλ‘ κ΅¬ννμμ΅λλ€.
μ΄μ κ°μ΄ μλΉμ€λ λ°±κ·ΈλΌμ΄λμμ μ§μμ μΌλ‘ μννκ³ μΆμ μμ μ΄ μμ κ²½μ° μ μ©νκ² μ¬μ©ν μ μμ΅λλ€.
μ€ν νλ©΄