Service 中的代码都是默认运行在主线程当中的,如果直接在Service 里处理一些耗时的逻辑,就很容易出现ANR(Application Not Responding )的情况。
所以,我们应该在Service 的每个具体的方法里开启一个子线程,然后在这里处理那些耗时的逻辑。
但是,这种Service 一旦启动,就会一直处于运行状态,必须调用stopService()或 stopSelf()方法,或者被系统回收,Service 才会停止。
因此,一个比较标准的Service 就可以写成如下形式:
kt
class MyService : Service() {
...
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
thread {
// 处理具体的逻辑
stopSelf()
}
return super.onStartCommand(intent, flags, startId)
}
}
Kotlin 提供了一种简单的开启线程的方式,写法如下:
ktthread { // 编写具体的逻辑 }
这里的thread是一个Kotlin内置的顶层函数,我们只需要在Lambda 表达式中编写具体的逻辑就可以了,连start()方法都不用调用,thread函数在内部帮我们全部都处理好了。
虽说这种写法并不复杂,但是总会有一些程序员忘记开启线程,或者忘记调用stopSelf()方法。
为了可以简单地创建一个异步的、会自动停止的Service ,Android 专门提供了一个 IntentService
类,这个类就很好地解决了前面所提到的两种尴尬。
kt
//首先,要求必须先调用父类的构造函数传入一个字符串。这个字符串可以随意指定,只在调试的时候有用。
class MyIntentService : IntentService("MyIntentService") {
//然后,要在子类中实现onHandleIntent()这个抽象方法,这个方法中可以处理一些耗时的逻辑,而不用担心ANR的问题,因为这个方法已经是在子线程中运行的了!
override fun onHandleIntent(intent: Intent?) {
Log.d("MyIntentService", "Thread id is ${Thread.currentThread().name}") // 打印当前线程的id
}
override fun onDestroy() {
super.onDestroy()
Log.d("MyIntentService", "onDestroy executed")
}
}
这里为了证实一下onHandleIntent确实是在子线程中运行的,我们在onHandleIntent()方法中打印了当前线程名。另外,根据 IntentService 的特性,这个Service 在运行结束后应该是会自动停止的,所以我们又重写了 onDestroy()方法,在这里也打印了一行日志,以证实Service 是不是停止了。
kt
class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
startIntentServiceBtn.setOnClickListener {
// 打印主线程的id
Log.d("MainActivity", "Thread id is ${Thread.currentThread().name}")
val intent = Intent(this, MyIntentService::class.java)
startService(intent)
}
}
}
其实IntentService 的启动方式和普通的Service 没什么两样。