文章目录
生命周期
startService和stopService方式
使用startService启动:
startService(Intent(this@MainActivity, MyService::class.java))
使用stopService停止:
stopService(Intent(this@MainActivity, MyService::class.java))
生命周期如下
启动时的生命周期如下:
Service启动后多次调用startService,只会执行onStartCommand,不会再次执行onCreate。生命周期如下:
bindService和unbindService方式
使用bindService启动,unbindService停止:
class MainActivity : AppCompatActivity() {
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d("~~~",Thread.currentThread().stackTrace[2].methodName)
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d("~~~",Thread.currentThread().stackTrace[2].methodName)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnBindService.setOnClickListener {
bindService(Intent(this@MainActivity, MyService::class.java), connection, BIND_AUTO_CREATE)
}
btnUnbindService.setOnClickListener {
unbindService(connection)
}
}
}
生命周期如下:
Service启动后多次执行bindService,不会执行任何回调。
如果一个Service既被startService启动了,又被bindService绑定了,那么单独调用stopService或unbindService都不会使Service销毁,直到stopService和unbindService都被调用后Service才会被销毁。
也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处于停止状态的时候才会被销毁。
onRebind回调
Service中还有个onRebind回调,如果Service未被销毁,并被同一个Activity多次绑定,并且onUnbind方法中返回的是true,则会执行onRebind回调。
例如:在MyService中编写以下代码:
class MyService : Service() {
val myBinder = MyBinder()
override fun onCreate() {
super.onCreate()
Log.d("~~~", Thread.currentThread().stackTrace[2].methodName)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("~~~", Thread.currentThread().stackTrace[2].methodName)
return super.onStartCommand(intent, flags, startId)
}
override fun onBind(intent: Intent?): IBinder? {
Log.d("~~~", Thread.currentThread().stackTrace[2].methodName)
return myBinder
}
override fun onUnbind(intent: Intent?): Boolean {
Log.d("~~~",Thread.currentThread().stackTrace[2].methodName)
return true
}
override fun onRebind(intent: Intent?) {
super.onRebind(intent)
Log.d("~~~",Thread.currentThread().stackTrace[2].methodName)
}
override fun onDestroy() {
super.onDestroy()
Log.d("~~~", Thread.currentThread().stackTrace[2].methodName)
}
inner class MyBinder : Binder() {
fun startTask() {
Log.d("~~~", Thread.currentThread().stackTrace[2].methodName)
}
}
}
在MainActivity中编写如下代码:
class MainActivity : AppCompatActivity() {
private lateinit var myBinder:MyService.MyBinder
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d("~~~",Thread.currentThread().stackTrace[2].methodName)
myBinder = service as MyService.MyBinder
myBinder.startTask()
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
}
private fun initView() {
btnStartService.setOnClickListener {
startService(Intent(this@MainActivity, MyService::class.java))
}
btnStopService.setOnClickListener {
stopService(Intent(this@MainActivity, MyService::class.java))
}
btnBindService.setOnClickListener {
bindService(Intent(this@MainActivity, MyService::class.java), connection, BIND_AUTO_CREATE)
}
btnUnbindService.setOnClickListener {
unbindService(connection)
}
}
}
运行程序,查看Log控制台。
点击startService:
~~~: onCreate
~~~: onStartCommand
点击bindService:
~~~: onBind
~~~: onServiceConnected
~~~: startTask
点击unbindService:
~~~: onUnbind
再点击bindService:
~~~: onServiceConnected
~~~: startTask
~~~: onRebind
再点击unbindService:
~~~: onUnbind
点击stopService:
~~~: onDestroy
Service 和 Thread
Service作为四大组件之一,本身和Thread是没有任何关系的。Service就像是一个没有界面的Activity,默认在主线程中运行,如果要在Service中执行耗时任务的话,需要在Service中开一个子线程。例如:
class MyService : Service() {
private val myBinder = MyBinder()
private val timerTask by lazy {
object : TimerTask() {
override fun run() {
Log.d("~~~", "${System.currentTimeMillis()}")
}
}
}
override fun onBind(intent: Intent?): IBinder? {
return myBinder
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 执行耗时任务,这里开启了一个定时器模拟耗时任务
Thread(Runnable {
Timer().schedule(timerTask, 0, 1000)
}).start()
return super.onStartCommand(intent, flags, startId)
}
inner class MyBinder : Binder() {
fun startTask() {
// 执行耗时任务,这里开启了一个定时器模拟耗时任务
Thread(Runnable {
Timer().schedule(timerTask, 0, 1000)
}).start()
}
}
override fun onDestroy() {
super.onDestroy()
timerTask.cancel()
}
}
在Service中开启子线程的好处是Service可以全局共享,多个
Activity绑定Service时,获取到的是同一个binder实例。
前台 Service
由于Service默默地在后台运行,优先级比较低,在系统内存不足时,系统会根据进程优先级从低到高来杀进程。如果想要Service不被系统轻易杀死,可以使用前台Service。
前台Service最明显的区别就在于他会在通知栏显示当前Service正在运行,优先级较高。来看一张效果图:
使用前台Service需要添加权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
Android8.0之后,通知栏需要添加channelId,使用前台Service示例如下:
class MyService : Service() {
private val myBinder = MyBinder()
override fun onBind(intent: Intent?): IBinder? {
return myBinder
}
override fun onCreate() {
super.onCreate()
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0)
val channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel("my_service", "My Background Service")
} else {
// If earlier version channel ID is not used
""
}
val builder = NotificationCompat.Builder(this, channelId)
val notification = builder.setOngoing(true)
.setContentTitle("content title")
.setContentText("content text")
.setContentIntent(pendingIntent)
.setSmallIcon(R.mipmap.ic_launcher)
.setPriority(PRIORITY_MIN)
.build()
startForeground(1, notification)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String): String {
val chan = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return channelId
}
inner class MyBinder : Binder() {
fun startTask() {
}
}
}
pendingIntent用于设置通知栏点击事件,channelID是Android8.0之后需要设置的参数,使用前要先调用NotificationManager的createNotificationChannel创建渠道。builder中可以设置通知栏的标题、内容、图标等属性。