销毁服务
本篇文章将销毁服务放在第一位,是因为销毁服务很重要,也因为在后面的描述中会经常提到销毁服务。
在服务完成任务后必须进行销毁,否则一直占用资源,导致内存溢出。
判断服务销毁的标志是,服务的 onDestroy() 方法执行了。
销毁服务的方式
-
使用 Context 的 stopService(Intent) 进行销毁。
-
使用服务的 stopSelf(int) 销毁任务,其中的参数是 onStartCommand(Intent, int, int) 方法的
startId
参数。销毁一个任务并不代表服务就会销毁,所有任务销毁了,服务才会销毁。 -
使用 unbindService(ServiceConnection) 解除所有绑定,服务必须要没有任何客户端绑定才有可能被销毁。
-
单纯的使用上面的某一种方式也不一定能销毁服务,因为具体的使用情况很复杂,可能需要集中销毁方式结合使用。
使用 Context 的 startService 启动
Intent intent = new Intent(MainActivity.this, LifecycleService.class);
startService(intent);
-
若服务没有运行,服务自动回调 onCreate() 方法和
[onStartCommand(Intent, int, int)](https://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int)) 方法。 -
若服务已经在运行,服务只回调 [onStartCommand(Intent, int, int)](https://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int)) 方法。可多次这样启动,每启动一次就调用一次
onStartCommand(Intent, int, int)
方法,每次调用都可看作是一次新的任务。 -
销毁服务的方式
-
无论这样启动了多少次,只需要调用一次 Context 的 stopService(Intent) 方法就可以销毁服务。
-
如果直接调用
Context
的 stopService(Intent) 方法结束服务是不人性化的,多数情况下,我们希望在任务执行完成后结束服务,这时就不能直接使用stopService(Intent)
方法,而应该使用Service
的 stopSelf(int) 方法,用于停止startId
所对应的任务,当所有任务都停止了,就表明所有任务都执行完成,此时服务会自动销毁。
启动前台服务
启动服务的方式与上面的 startService 相同,只是在 Service 的 onStartCommand
里使用startForeground()方法将服务变为前台服务并创建通知,如下:
startForeground(startId, NotificationUtil.createNotification(this));
NotificationUtil 是我自己写的一个创建通知的工具类。
- 在启动了后台服务后,仍然可以启动前台服务。当然,前台服务一般是单独创建一个服务来处理事情,不会与后台服务同在一个类里。
- 结束服务的方式与上面的启动后台服务的方式相同,结束服务后,通知自动消失。
使用 Context 的 bindService 绑定服务
绑定 Service 后,可以与 Service 之间进行通信。绑定方式如下:
bindService(new Intent(MainActivity.this, LifecycleService.class), mServiceConnection,
Context.BIND_AUTO_CREATE);
mServiceConnection用于界面和 Service 的连接。
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
Timber.e("onServiceConnected");
if (service instanceof LifecycleService.MyBinder) {
mBound = true;
LifecycleService.MyBinder binder = (LifecycleService.MyBinder) service;
mLifecycleService = binder.getService();
}
}
@Override public void onServiceDisconnected(ComponentName name) {
Timber.e("onServiceDisconnected");
mBound = false;
}
};
onServiceConnected方法表示连接成功,然后从其中获取Binder,在 Binder 中定义了一个方法用于获取 Service,这样就可以直接调用 Service 里的方法了。Binder在 Service中实现的,如下。
private final IBinder mBinder = new MyBinder();
public class MyBinder extends Binder {
LifecycleService getService() {
return LifecycleService.this;
}
}
@Override public IBinder onBind(Intent intent) {
return mBinder;
}
这里的onBind
的返回值是不能返回 null 的。若返回 null,不会回调 onServiceConnected
方法,也不能销毁服务。
- 使用
bindService()
方法绑定服务,服务是不会回调 onStartCommand(Intent, int, int) 方法的,服务的所有客户端都解绑之后,服务就自动销毁。 - 既绑定了服务,又使用 startService(Intent) 启动了前台或者后台服务,则服务停止的条件是解除所有绑定(
unbindService(ServiceConnection)
)以及所有任务执行完成(stopSelf(int)
),二者缺一不可。
官方文档说了:为了确保应用的安全性,请始终使用显式 Intent 启动或绑定 Service,且不要为服务声明 Intent 过滤器。
网友评论