Android中startService和bindService的区别

Service属于android四大组件之一,在很多地方经常被用到。开启Service有两种不同的方式:startService和bindService。不同的开启方式,Service执行的生命周期方法也不同。
首先,先看一下Service都有哪些生命周期方法。
要想使用Service需要写一个自己的MyService类,并继承Service。还要在清单文件中声明一下。


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就没有关联,不受影响,独立运行。
2、bindService开启服务以后,与activity存在关联,退出activity时必须调用unbindService方法,否则会报ServiceConnection泄漏的错误。

最后还有一点,同一个服务可以用两种方式一同开启,没有先后顺序的要求,MyService的onCreate只会执行一次。
关闭服务需要stopService和unbindService都被调用,也没有先后顺序的影响,MyService的onDestroy也只执行一次。但是如果只用一种方式关闭服务,不论是哪种关闭方式,onDestroy都不会被执行,服务也不会被关闭。这一点需要注意。

你可能感兴趣的:(Android中startService和bindService的区别)