1、Service 的生命周期
- 服务 Service 是 Android 的四大组件之一,常用在看不见页面的高级场合,例如闹钟服务、通知服务等。
- Service 与 Activity 相比,不同之处在于没有对应的页面,相同之处在于有生命周期。
下面是 Service 与生命周期有关的方法:
- onCreate:创建服务。
- onStart:开始服务。Android 2.0 以下版本使用,已废弃。
- onStartCommand:开始服务。Android 2.0 及以上版本使用。
- onDestroy:销毁服务。
- onBind:绑定服务。
- onRebind:重新绑定。该方法只有当上次 onUnbind 返回 true 的时候才会被调用。
- onUnbind:解除绑定。默认为 false。
Service 存在多种启停方法,每种启停方式都对应不同的周期方法,下面分别叙述 3 种启停方式及其生命周期说明:
- 普通启停
普通启停是最简单的用法,下面是该方式的服务代码:
public class NormalService extends Service {
private static final String TAG = "NormalService";
private void refresh(String text) {
Log.d(TAG, text);
ServiceNormalActivity.showText(text);
}
@Override
public void onCreate() { // 创建服务
refresh("onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startid) { // 启动服务,Android2.0以下使用
refresh("onStart");
super.onStart(intent, startid);
}
@Override
public int onStartCommand(Intent intent, int flags, int startid) { // 启动服务,Android2.0以上使用
Log.d(TAG, "测试服务到此一游!");
refresh("onStartCommand. flags=" + flags);
return START_STICKY;
}
@Override
public void onDestroy() { // 销毁服务
refresh("onDestroy");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) { // 绑定服务。普通服务不存在绑定和解绑流程
refresh("onBind");
return null;
}
@Override
public void onRebind(Intent intent) { // 重新绑定服务
refresh("onRebind");
super.onRebind(intent);
}
@Override
public boolean onUnbind(Intent intent) { // 解绑服务
refresh("onUnbind");
return true;
}
}
启动服务:
停止服务:
- 立即绑定
绑定方式的服务定义有所不同,因为绑定的服务可能运行于另一个进程,所以必须定义一个 Binder 对象用来进行进程间的通信。下面是一个绑定方式的服务代码:
public class BindImmediateService extends Service {
private static final String TAG = "BindImmediateService";
// 创建一个粘合剂对象
private final IBinder mBinder = new LocalBinder();
// 定义一个当前服务的粘合剂,用于将该服务黏到活动页面的进程中
public class LocalBinder extends Binder {
public BindImmediateService getService() {
return BindImmediateService.this;
}
}
private void refresh(String text) {
Log.d(TAG, text);
BindImmediateActivity.showText(text);
}
@Override
public void onCreate() { // 创建服务
refresh("onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startid) { // 启动服务
refresh("onStart");
super.onStart(intent, startid);
}
@Override
public void onDestroy() { // 销毁服务
refresh("onDestroy");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) { // 绑定服务。返回该服务的粘合剂对象
Log.d(TAG, "绑定服务开始旅程!");
refresh("onBind");
return mBinder;
}
@Override
public void onRebind(Intent intent) { // 重新绑定服务
refresh("onRebind");
super.onRebind(intent);
}
@Override
public boolean onUnbind(Intent intent) { // 解绑服务。返回false表示只能绑定一次,返回true表示允许多次绑定
Log.d(TAG, "绑定服务结束旅程!");
refresh("onUnbind");
return true;
}
}
启动:
停止:
- 延迟绑定
延迟绑定与立即绑定的区别在于:延迟绑定是在页面上先通过 startService 方法启动服务,然后通过 bindService 方法绑定已存在的服务。这样,因为启动操作在先,所以解绑操作只能撤销绑定操作,而不能撤销启动操作。
由于解绑服务不能停止服务,因此存在再次绑定服务的可能。
public class BindDelayService extends Service {
private static final String TAG = "BindDelayService";
// 创建一个粘合剂对象
private final IBinder mBinder = new LocalBinder();
// 定义一个当前服务的粘合剂,用于将该服务黏到活动页面的进程中
public class LocalBinder extends Binder {
public BindDelayService getService() {
return BindDelayService.this;
}
}
private void refresh(String text) {
Log.d(TAG, text);
BindDelayActivity.showText(text);
}
@Override
public void onCreate() { // 创建服务
refresh("onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startid) { // 启动服务
refresh("onStart");
super.onStart(intent, startid);
}
@Override
public void onDestroy() { // 销毁服务
refresh("onDestroy");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) { // 绑定服务。返回该服务的粘合剂对象
Log.d(TAG, "绑定服务开始旅程!");
refresh("onBind");
return mBinder;
}
@Override
public void onRebind(Intent intent) { // 重新绑定服务
refresh("onRebind");
super.onRebind(intent);
}
@Override
public boolean onUnbind(Intent intent) { // 解绑服务。返回false表示只能绑定一次,返回true表示允许多次绑定
Log.d(TAG, "绑定服务结束旅程!");
refresh("onUnbind");
return true;
}
}
启动:
绑定:
解绑:
停止:
从日志中可以看到,延迟绑定与立即绑定两种方式的生命周期区别在于:
- 延迟绑定的首次绑定操作只调用 onBind 方法,再次绑定只调用 onRebind 方法(是否允许再次绑定要看上次 onUnbind 方法的返回值)。
- 延迟绑定的解绑操作只调用 onUnbind 方法。
2、推送服务到前台
服务没有自己的布局文件,也就意味着无法直接在页面上显示,要想了解服务的运行情况,要么通过打印日志,要么获取某个页面的静态对象,然后在该页面上显示运行结果。然而活动页面有自身的生命周期,极有可能发生服务尚在运行但页面早已退出的情况,所以该方式不可靠。
服务内部的启停方法有对应的两个函数:
- startForeground:把当前服务切换到前台运行。第一个参数表示通知的编号,第二个参数表示 Notification 对象,意味着切换到前台就是展示到通知栏。
- stopForeground:停止前台运行。参数为 true 表示清除通知,参数为 false 表示不清除。
从 Android 9.0 开始,在服务中正常调用 startForeground 方法,还需修改 AndroidManifest.xml,添加如下所示的前台服务权限配置:
<!-- 允许前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />