Service
Service
是Android
中实现程序后台运行的解决方案,它非常适合执行那些不需要和用户交互而且还要求长期运行的任务。Service
的运行不依赖于任何用户界面,即使程序被切换到后台,或者用户打开了另外一个应用程序,Service
仍然能够保持正常运行。
需要注意的是,Service
并不是运行在一个独立的进程当中的,而是依赖于创建Service
时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的Service
也会停止运行。
另外,Service
并不会自动开启线程,所有的代码都是默认运行在主线程当中的。也就是说,如有需要,就要在Service
的内部手动创建子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞的情况。
在
Android
和iOS
大移动操作系统中,iOS
一开始是不支持后台的,后来意识到这个功能的重要性,才逐渐加入了部分后台功能。而Android
正好相反,一开始支持丰富的后台功能,后来意识到后台太过开放的弊端,于是逐渐削减了后台功能。不管怎么说,用于实现后台功能的Service
属于四大组件之 一,其重要程度不言而喻。
1 Service
的启动流程
Process A
进程采用Binder IPC
向system_server
进程发起startService
请求;system_server
进程接收到请求后,向zygote
进程发送创建进程的请求;zygote
进程fork
出新的子进程Remote Service
进程;Remote Service
进程,通过Binder IPC
向sytem_server
进程发起attachApplication
请求;system_server
进程在收到请求后,进行一系列准备工作后,再通过binder IPC
向remote Service
进程发送scheduleCreateService
请求;Remote Service
进程的binder
线程在收到请求后,通过Handler
向主线程发送CREATE_SERVICE
消息;- 主线程在收到
Message
后,通过发射机制创建目标Service
,并回调Service.onCreate()
方法;
到此,服务便正式启动完成。当创建的是本地服务或者服务所属进程已创建时,则无需经过上述步骤2
、3
,直接 创建服务即可。
Context.startService
运行时序图:
Context.bindService()
运行时序图:
2 Service
的生命周期
2.1 启动方式
Service
的启动方式主要有两种,分别是startService
和bindService
。
下图是startService
和bindService
两种方式启动Service
的生命周期示意图:
用startService
方法启动的服务,与启动者没有关系,也不会进行通信。即使启动着销毁了,服务仍然在运行。停止服务使用stopService
方法。(onCreate -> onStartCommand -> onDestroy
)
用bindService
方法启动的服务,服务和启动者绑定,可以进行通信。当启动者销毁时,对应的Service
也会销毁(Service
的生命周期与其绑定者息息相关)。停止服务使用unbindService
方法。(onCreate -> onbind -> onUnbind -> onDestroy
)
生命周期方法:
onCreate()
:创建服务。首次创建服务时,系统会调用此方法(如果服务已经运行,则不会调用此方法),该方法只调用一次onStartCommane()
:开始服务。当另一个组件通过调用startService
方法启动服务时,系统将调用此方法onDestory()
:销毁服务。当服务不再使用且将要销毁的时候,系统将调用此方法onBind()
:绑定服务。当另一个组件通过调用bindService
方法与服务绑定时,系统将调用此方法onUnbind()
:解绑服务。当另一个组件调用unbindeService
方法与服务解绑时,系统将调用此方法onRebind()
:当旧的组件与服务解绑后,另一个新的组件与服务绑定,onRebind
方法返回true
时,系统将调用此方法
用startService
方法开启服务,如果服务已经开启,多次执行startService
不会重复的执行onCreate
方法, 而是会调用onStartCommand
方法(onStart
方法已弃用)。注意,虽然每调用一次startService()
方法,onStartCommand()
就会执行一次,但实际上每个Service
只会存在一个实例。所以不管你调用了多少次startService()
方法,只需调用一次stopService()
或stopSelf()
方法,Service
就会停止。
用bindService
方法开启服务,如果服务已经开启,多次执行bindService
时,onCreate
和onBind
方法并不会被多次调用。
用startService + bindService
启动的服务,停止服务应同时使用stopService + unbindService
。 根据Android
系统的机制,一个Service
只要被启动或者被绑定了之后,就会处于运行状态,必须要让以上两种条件同时不满足,Service
才能被销毁。所以,这种情况下要同时调用stopService()
和unbindService()
方法,onDestroy()
方法才会执行。
通常情况下,如果我们希望Service
一旦启动就立刻去执行某个动作,就可以将逻辑写在onStartCommand()
方法里。而当Service
销毁时,我们又应该在onDestroy()
方法中回收那些不再使用的资源。
2.2 startService
创建一个Service
:
以下是MyService
中的代码:
class MyService : Service() {
override fun onBind(intent: Intent): IBinder {
TODO("Return the communication channel to the service.")
}
}
并且已经在AndroidManifest.xml
中完成了注册。**需要注意,每一个Service
都需要在AndroidManifest.xml
文件中进行注册才能生效,这是Android
四大组件共有的特点。**代码如下所示:
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
</service>
MyService
是继承自系统的Service
类的, Service
类本身是抽象类,有一个抽象方法onBind()
方法,此方法是必须重写的,即使用不到。
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
@Nullable
public abstract IBinder onBind(Intent intent);
}
启动和停止Service
主要是借助Intent
来实现的。
class MyService : Service() {
override fun onBind(intent: Intent): IBinder {
TODO("Return the communication channel to the service.")
}
override fun onCreate() {
super.onCreate()
Log.e("CAH - MyService", "onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e("CAH - MyService", "onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
Log.e("CAH - MyService", "onDestroy")
super.onDestroy()
}
}
// 启动Service
startServiceBtn.setOnClickListener {
val intent = Intent(this, MyService::class.java)
startService(intent)
}
// 停止Service
stopServiceBtn.setOnClickListener {
val intent = Intent(this, MyService::class.java)
stopService(intent)
}
点击startServiceBtn
,打印日志:
// CAH - MyService: onCreate
// CAH - MyService: onStartCommand
多次点击startServiceBtn
,打印日志:
// CAH - MyService: onStartCommand
// CAH - MyService: onStartCommand
// CAH - MyService: onStartCommand
只调用onStartCommand
方法,不调用onCreate
方法。
点击stopServiceBtn
按钮:
// CAH - MyService: onDestroy
另外,Service
也可以自行停止运行,只需要在Service
内部调用stopSelf()
方法即可。
从Android 8.0
系统开始,应用的后台功能被幅削减。只有当应用保持在前台可见状态的情况下,Service
才能保证稳定运行,一旦应用进入后台之后,Service
随时都有可能被系统回收。之所以做这样的改动,是为了防止许多恶意的应用程序长期在后台占用手机资源,从而导致手机变得越来越卡。
Service
的onStartCommand
方法的返回值各代表什么意思?
调用Context.startService
方式启动Service
时,如果Android
面临内存匮乏的问题,可能会销毁当前运行的Service
,待内存充足时可以重建Service
。而Service
被Android
系统强制销毁并再次重建的行为依赖于Service
的onStartCommand()
方法的返回值。
以下是onStartCommand
的源码:
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
@Deprecated
public void onStart(Intent intent, int startId) {
}
}
START_STICKY
:重传Intent
。使用这个返回值时,如果在执行完onStartCommand
后,服务被异常kill
掉,系统会自动重启该服务 ,并且onStartCommand
方法会执行,onStartCommand
方法中的intent
值为null
。 适用于媒体播放器或类似服务。
START_STICKY_COMPATIBILITY
:START_STICKY
的兼容性版本,不保证onStartCommand
将在被杀死后再次调用。
sticky [ˈstɪki] 黏性的 compatibility [kəmˌpætəˈbɪləti] 共存;和睦相处;(计算机设备的)兼容性
2.3 bindService
用bindService
的方法启动的服务,和调用者之间是典型的Client-Server
模式。调用者是client
,Service
则是Server
端。Service
只有一个,但绑定到Service
上面的Client
可以有一个或很多个。
那么,Service
与Activity
怎么实现通信的?—— 通过Binder
对象
Service
中添加一个继承Binder
的内部类,并添加相应的逻辑方法Service
中重写Service
的onBind
方法,返回定义的内部类实例Activity
中绑定服务,重写ServiceConnection
,onServiceConnected
时返回的IBinder
(Service
中的Binder
)调用逻辑方法
另外,Service
也可以通过Broadcast
广播与Activity
通信
比如说,目前我们希望在MyService
里提供一个下载功能,然后在Activity
中可以决定何时开始下载,以及随时查看下载进度。实现这个功能的思路是创建一个专门的Binder
对象来对下载功能进行管理。这就需要借助onBind()
方法了。
修改MyService
中的代码,如下所示:
class MyService : Service() {
private val mBinder = DownloadBinder()
class DownloadBinder : Binder() {
fun startDownload() {
Log.e("CAH - MyService - DownloadBinder", "startDownload")
}
fun getProgress(): Int {
Log.e("CAH - MyService - DownloadBinder", "getProgress")
return 0
}
}
override fun onBind(intent: Intent): IBinder {
Log.e("CAH - MyService", "onBind")
return mBinder
}
override fun onCreate() {
super.onCreate()
Log.e("CAH - MyService", "onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e("CAH - MyService", "onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
Log.e("CAH - MyService", "onDestroy")
super.onDestroy()
}
}
可以看到,这里新建了一个DownloadBinder
类,并让它继承自Binder
,然后在它的内部提供了开始下载以及查看下载进度的方法。接着,在MyService
中创建了DownloadBinder
的实例,然后在onBind()
方法里返回了这个实例,这样MyService
中的工作就全部完成了。
在MainActivity
(启动者)中:
class MainActivity : BaseActivity() {
private lateinit var bindServiceBtn: Button
private lateinit var unbindServiceBtn: Button
lateinit var downloadBinder: MyService.DownloadBinder
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
downloadBinder = service as MyService.DownloadBinder
downloadBinder.startDownload()
downloadBinder.getProgress()
}
override fun onServiceDisconnected(name: ComponentName?) {
TODO("Not yet implemented")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bindServiceBtn = findViewById(R.id.bindServiceBtn)
unbindServiceBtn = findViewById(R.id.unbindServiceBtn)
bindServiceBtn.setOnClickListener {
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
unbindServiceBtn.setOnClickListener {
unbindService(connection)
}
}
}
这里首先创建了一个ServiceConnection
的匿名实现类,并在里面重写了onServiceConnected()
方法和onServiceDisconnected()
方法。 onServiceConnected()
方法方法会在Activity
(启动者)与Service
成功绑定的时候调用,而 onServiceDisconnected()
方法只有在Service
的创建进程崩溃或者被杀掉的时候才会调用,这个方法不太常用。
在onServiceConnected()
方法中,通过向下转型得到了DownloadBinder
的实例,有了这个实例,Activity
和Service
就联系起来了。现在就可以在Activity
中根据具体的场景来调用DownloadBinder
中的任何public
方 法,即实现了指挥Service
干什么Service
就去干什么的功能。这里仍然只是做了个简单的测试,在onServiceConnected()
方法中调用了DownloadBinder
的startDownload()
和getProgress()
方法。
现在Activity
和Service
其实还没进行绑定呢,这个功能是在Bind Service
按钮的点击事件里完成的。构建了一个Intent
对象,然后调用bindService()
方法将MainActivity
和MyService
进行绑定。bindService()
方法接收3
个参数:
- 第一个参数是构建出的
Intent
对象 - 第二个参数是前面创建出的
ServiceConnection
的实例 - 第三个参数则是一个标志位,这里传入
BIND_AUTO_CREATE
表示在Activity
和Service
进行绑定后自动创建Service
。 这会使得MyService
中的onCreate()
方法得到执行,但onStartCommand()
方法不会执行
如果我们想解除Activity
和Service
之间的绑定调用一下unbindService()
方法就可以了。
运行程序,点击Bind Service
按钮:
// CAH - MyService: onCreate
// CAH - MyService: onBind
// CAH - MyService - DownloadBinder: startDownload
// CAH - MyService - DownloadBinder: getProgress
连续点击Bind Service
按钮,发现没有日志打印,说明onCreate
方法和onBind
方法只调用了一次。
点击Unbind Service
按钮:
// CAH - MyService: onUnbind
// CAH - MyService: onDestroy
2.4 startService
+bindService
如果只是想要启动一个后台服务长期进行某项任务,那么使用startService
便可以了。如果还想要与正在运行的Service
取得联系,那么有两种方法:一种是使用broadcast
,另一种是使用bindService
。
2.4.1 startService
-> bindService
启动服务:
val intent = Intent(this, MyService::class.java)
startService(intent)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
打印日志:
// CAH - MyService: onCreate
// CAH - MyService: onStartCommand
// CAH - MyService: onBind
// CAH - MyService - DownloadBinder: startDownload
// CAH - MyService - DownloadBinder: getProgress
连续启动服务,打印日志:
// CAH - MyService: onStartCommand
// CAH - MyService: onStartCommand
停止服务(stopService
-> unbindService
或unbindService
-> stopService
):
val intent = Intent(this, MyService::class.java)
stopService(intent)
unbindService(connection)
打印日志:
// CAH - MyService: onUnbind
// CAH - MyService: onDestroy
停止服务(stopService
):
val intent = Intent(this, MyService::class.java)
stopService(intent)
不打印任何日志。
停止服务(unbindService
):
val intent = Intent(this, MyService::class.java)
unbindService(connection)
打印日志:
// CAH - MyService: onUnbind
2.4.2 bindService
-> startService
启动服务:
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
startService(intent)
打印日志:
// CAH - MyService: onCreate
// CAH - MyService: onBind
// CAH - MyService: onStartCommand
// CAH - MyService - DownloadBinder: startDownload
// CAH - MyService - DownloadBinder: getProgress
连续启动服务,打印日志:
// CAH - MyService: onStartCommand
// CAH - MyService: onStartCommand
停止服务(stopService
-> unbindService
或unbindService
-> stopService
):
val intent = Intent(this, MyService::class.java)
stopService(intent)
unbindService(connection)
打印日志:
// CAH - MyService: onUnbind
// CAH - MyService: onDestroy
停止服务(stopService
):
val intent = Intent(this, MyService::class.java)
stopService(intent)
不打印任何日志。
停止服务(unbindService
):
val intent = Intent(this, MyService::class.java)
unbindService(connection)
打印日志:
// CAH - MyService: onUnbind
总结:
如果只执行stopService
,Service.onDestroy
方法不会立即执行。 但是,在Activity
退出的时候,会执行Service.OnDestroy
;
如果只执行unbindService
,只有onUnbind
方法会执行,onDestory
不会执行;
如果要完全退出Service
,那么就得执行unbindService() + stopService()
;
3 Service
设置前台服务&提高优先级
3.1 使用前台Service
从Android 8.0
系统开始,只有当应用保持在前台可见状态的情况下,Service
才能保证稳定运行,一旦应用进入后台之后,Service
随时都有可能被系统回收。而如果希望Service
能够一直保持运行状态,就可以考虑使用前台Service
。 前台Service
和普通Service
最大的区别就在于,它一直会有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果,如图所示:
由于状态栏中一直有一个正在运行的图标,相当于我们的应用以另外一种形式保持在前台可见状态,所以系统不会倾向于回收前台Service
。另外,用户也可以通过下拉状态栏清楚地知道当前什么应用正在运行,因此也不存在某些恶意应用长期在后台偷偷占用手机资源的情况。
代码如下所示:
class MyService : Service() {
...
override fun onCreate() {
super.onCreate()
Log.e("CAH", "onCreate executed")
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"my_service",
"前台Service通知",
NotificationManager.IMPORTANCE_DEFAULT
)
manager.createNotificationChannel(channel)
}
val intent = Intent(this, StackActivity::class.java)
val pi = PendingIntent.getActivity(this, 0, intent, 0)
val notification = NotificationCompat.Builder(this, "my_service")
.setContentTitle("This is content title")
.setContentText("This is content text")
.setSmallIcon(R.drawable.chang)
.setColor(Color.RED)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.cai))
.setContentIntent(pi)
.build()
startForeground(1, notification)
}
...
}
startForeground()
方法接收两个参数:第一个参数是通知的id
,类似于notify()
方法的第一个参数;第二个参数则是构建的Notification
对象。调用startForeground()
方法后就会让MyService
变成一个前台Service
,并在系统状态栏显示出来。
另外,从Android 9.0
系统开始,使用前台Service
必须在AndroidManifest.xml
文件中进行权 限声明才行,如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
...
</manifest>
3.2 设置Service
的优先级
在intent-fillter
中设置Service
的优先级
android:priority="1000"
,其中数字越小优先级越低,1000
代表优先级最高。 不过这个的效果并没有设为前台服务好,这个1000
的优先级顶多与前台服务的优先级相同。其实Priority
属性不仅仅可以用于Service
,只要是有intent-fillter
的组件都可以,比如说Activity
和BroadcastReceiver
,这个属性多是用来按指定一个执行顺序的。
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
</intent-filter>
</service>
3.3 将Service设为黏性服务
只需要将Service
的onStartCommand()
方法的返回值设为START_STICKY
即可:
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_STICKY
}
3.4 在Service.onDestroy()
里重启服务
实现原理是Service
注册广播,当服务被杀死的时候发送一条广播,监听到对应广播后在broadcastReceiver
的onReceive()
方法里重新开启服务。
缺点就是很可能服务是被因为app
直接被kill
掉了,并不会走onDestroy()
。
4 IntentService
4.1 原理
Service
中的代码都是默认运行在主线程当中的,如果直接在Service
里处理一些耗时的逻辑,就很容易出现ANR(Application Not Responding)
的情况。
这个时候就需要用到Android
多线程编程的技术了,在Service
的每个具体的方法里开启一个子线程,然后在这里处理那些耗时的逻辑。一个比较标准的Service
就可以写成如下形式:
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e("MyService", "onStartCommand: ")
thread {
// 处理逻辑
}
return super.onStartCommand(intent, flags, startId)
}
但是,这种Service
一旦启动,就会一直处于运行状态,必须调用stopService()
或stopSelf()
方法或者被系统回收,Service
才会停止。所以,如果想要实现让一个Service
在执行完毕后自动停止的功能,就可以这样写:
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e("MyService", "onStartCommand: ")
thread {
// 处理逻辑
stopSelf()
}
return super.onStartCommand(intent, flags, startId)
}
虽说这种写法并不复杂,但是总会有一些程序员忘记开启线程,或者忘记调用stopSelf()
方法。为了可以简单地创建一个异步的、会自动停止的Service
,Android
专门提供了一个IntentService
类,这个类就很好地解决了前面所提到的两种问题。
IntentService
是Service
的子类,默认开启了一个工作线程ServiceHandler
,使用这个工作线程逐一处理所有启动请求,在任务执行完毕后会自动停止服务。只要实现一个方法onHandleIntent
,该方法会接收每个启动请求的Intent
,能够执行后台工作和耗时操作。
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler { // 1
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1); // 4
}
}
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper(); // 2
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
// 3
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
实现原理:
- 创建一个名叫
ServiceHandler
的内部类,ServiceHandler extends Handler
- 在
IntentService.onCreate
方法中,获取当前线程的Looper
,并且将ServiceHandler
和当前线程的Looper
、MessageQueue
绑定 - 在
IntentService.onStartCommand -> onStart
方法中,将intent
依次插入到MessageQueue
中,逐个处理 - 在
ServiceHandler.handleMessage
方法中,调用ServiceHandler.onHandleIntent
方法,处理完成后,会自动停止
可以启动IntentService
多次,而每一个耗时操作会以队列的方式在IntentService
的onHandlerIntent
回调方法中执行,并且,每一次只会执行一个工作线程,执行完第一个再执行第二个。并且等待所有消息都执行完后才终止服务。
IntentService
可以用作后台下载任务,静默上传等。
4.2 实现
新建一个MyIntentService
类继承自IntentService
,代码如下所示:
class MyIntentService : IntentService("MyIntentService") {
override fun onHandleIntent(intent: Intent?) {
Log.e("MyIntentService", "Thread id is ${Thread.currentThread().name}")
}
override fun onDestroy() {
super.onDestroy()
Log.e("MyIntentService", "onDestroy")
}
}
首先要求必须先调用父类的构造函数,并传入一个字符串,这个字符串可以随意指定,只在调试的时候有用。然后要在子类中实现onHandleIntent()
这个抽象方法,这个方法中可以处理一些耗时的逻辑,而不用担心ANR
的问题,因为这个方法已经是在子线程中运行的了。
这里为了证实一下,在onHandleIntent()
方法中打印了当前线程名。另外,根据IntentService
的特性,这个Service
在运行结束后应该是会自动停止的,所以我们又重写了onDestroy()
方法,在这里也打印了一行日志,以证实Service
是不是停止了。
最后不要忘记,Service
都是需要在AndroidManifest.xml
里注册的,如下所示:
<service
android:name=".MyIntentService"
android:enabled="true"
android:exported="true" />
启动IntentService
,代码如下所示:
class MainActivity : BaseActivity() {
private lateinit var startIntentServiceBtn: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startIntentServiceBtn = findViewById(R.id.startIntentServiceBtn)
startIntentServiceBtn.setOnClickListener {
Log.e("MainActivity", "Thread id is ${Thread.currentThread().name}")
val intent = Intent(this, MyIntentService::class.java)
startService(intent)
}
}
}
可以看到,IntentService
的启动方式和普通的Service
没什么不同。
观察Logcat
中的打印日志,如下所示:
// MainActivity: Thread id is main
// MyIntentService: Thread id is IntentService[MyIntentService]
// MyIntentService: onDestroy
可以看到,不仅MyIntentService
和MainActivity
所在的线程名不一样,而且onDestroy()
方法也得到了执行,说明MyIntentService
在运行完毕后确实自动停止了,集开启线程和自动停止于一身。
参考
https://www.codeleading.com/article/57973935944/