Service属于android四大组件之一,在很多地方经常被用到。开启Service有两种不同的方式:startService和bindService。不同的开启方式,Service执行的生命周期方法也不同。
首先,先看一下Service都有哪些生命周期方法。
要想使用Service需要写一个自己的MyService类,并继承Service。还要在清单文件中声明一下。
<service android:name=".MyService"/>
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("call", "onBind");
return null;
}
@Override
public void onCreate() {
Log.e("call", "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("call", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e("call", "onDestroy");
super.onDestroy();
}
}
startService开启服务和结束服务稍微简单一点。
//开启服务
Intent service = new Intent(this, MyService.class);
startService(service);
//结束服务
stopService(service);
开启服务时,调用一次startService,生命周期执行的方法依次是:
onCreate() ==> onStartCommand();
调用多次startService,onCreate只有第一次会被执行,而onStartCommand会执行多次。
结束服务时,调用stopService,生命周期执行onDestroy方法,并且多次调用stopService时,onDestroy只有第一次会被执行。
bindService开启服务就多了一些内容。
//开启服务
Intent service = new Intent(this, MyService.class);
MyConnection conn = new MyConnection();
//第一个参数:Intent意图
//第二个参数:是一个接口,通过这个接口接收服务开启或者停止的消息,并且这个参数不能为null
//第三个参数:开启服务时的操作,BIND_AUTO_CREATE代表自动创建service
bindService(service, conn, BIND_AUTO_CREATE);
bindService的方法参数需要一个ServiceConnection接口的实现类对象,我们自己写一个MyConnection类,并实现里面的方法。
private class MyConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//只有当我们自己写的MyService的onBind方法返回值不为null时,才会被调用
Log.e("call","onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
//这个方法只有出现异常时才会调用,服务器正常退出不会调用。
Log.e("call","onServiceDisconnected");
}
}
//结束服务
unbindService(conn);
bingService开启服务时,根据生命周期里onBind方法的返回值是否为空,有两种情况。
1、onBind返回值是null;
调用bindService开启服务,生命周期执行的方法依次是:
onCreate() ==> onBind();
调用多次bindService,onCreate和onBind也只在第一次会被执行。
调用unbindService结束服务,生命周期执行onDestroy方法,并且unbindService方法只能调用一次,多次调用应用会抛出异常。使用时也要注意调用unbindService一定要确保服务已经开启,否则应用会抛出异常。
2、onBind返回值不为null;
看一下android对于onBind方法的返回类型IBinder的介绍,字面上理解是IBinder是android提供的进程间和跨进程调用机制的接口。而且返回的对象不要直接实现这个接口,应该继承Binder这个类。
那么我们就在自己写的MyService里创建一个内部类MyBinder,让他继承Binder,并在onBind方法里返回MyBinder的对象。
@Override
public IBinder onBind(Intent intent) {
Log.e("call", "onBind");
MyBinder mbind = new MyBinder();
Log.e("call", mbind.toString());
return mbind;
}
private class MyBinder extends Binder{
public void systemOut(){
System.out.println("该方法在MyService的内部类MyBinder中");
}
}
这时候调用bindService开启服务,生命周期执行的方法依次是:
onCreate() ==> onBind() ==> onServiceConnected();
可以发现我们自己写的MyConnection类里的onServiceConnected方法被调用了。调用多次bindService,onCreate和onBind都只在第一次会被执行,onServiceConnected会执行多次。
并且我们注意到onServiceConnected方法的第二个参数也是IBinder类型的,不难猜测onBind()方法返回的对象被传递到了这里。打印一下两个对象的地址可以证明猜测是正确的。
也就是说我们可以在onServiceConnected方法里拿到了MyService服务的内部类MyBinder的对象,通过这个内部类对象,只要强转一下,我们可以调用这个内部类的非私有成员对象和方法。
调用unbindService结束服务和上面相同,unbindService只能调用一次,onDestroy也只执行一次,多次调用会抛出异常。
接下来我们说一下startService和bindService开启服务时,他们与activity之间的关心。
1、startService开启服务以后,与activity就没有关联,不受影响,独立运行。ServiceConnection
2、bindService开启服务以后,与activity存在关联,退出activity时必须调用unbindService方法,否则会报ServiceConnection泄漏的错误。
最后还有一点,同一个服务可以用两种方式一同开启,没有先后顺序的要求,MyService的onCreate只会执行一次。
关闭服务需要stopService和unbindService都被调用,也没有先后顺序的影响,MyService的onDestroy也只执行一次。但是如果只用一种方式关闭服务,不论是哪种关闭方式,onDestroy都不会被执行,服务也不会被关闭。这一点需要注意。