众所周知,Service会根据不同的启动方式,会有不同的生命周期的回调。startService和bindService的区别就是该service是否可以和启动它的组件(比如activity)通信,因为bindService可以拿到Service的binder,binder就是用来实现IPC!
一、onCreate
创建Service实例时被调用,但是这里的Service实例却和Activity的实例不太一样。Activity可以通过设置启动模式获取一个或多个实例,但Service不管设置2种启动模式的哪一种,都只会得到一个实例对象。毕竟Service是要与Activity交互的,没必要为每个“客户端”都单独设置一个“服务端”。在onCreate中我们做的,依旧是初始化,创建数据缓存、线程池等。
参考IntentService源码:
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
Service默认是在主线程中执行,除非要提高服务的优先级,防止应用进入后台时被kill。否则,最好创建新的线程、线程池,不要把一个后台任务放在Service主线程。
二、onStart
调用startService方法时调用的,我们的后台任务一般都会放在这里执行,你可以通过intent获取startService方法传递的参数,这里依然以IntentService为例看下它的实现方式:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
三、onBind
调用bindService方法时调用,如果使用bindService方式来启动服务的话,一般发生在Activity需要与Service进行通信的场景(比如说音乐播放器app里面就会用到),而Android的IPC主要是通过binder来实现的(也可以通过socket,在系统服务用的比较多),所以这里方法的返回值就需要一个binder实例。这里简单说下binder的实现机制,其实就是一套PC上的C/S模式,用户通过bindService接口获取到Service的代理,然后通过这个代理来跟Service通信。
public class MyService extends Service {
Binder mService = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
};
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mService;
}
}
// call in activity
bindService(new Intent(this, MyService.class), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mServiceProxy = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, 0);
这里的代理包括:本地和远程代理两种,它们是按照service和activity是否在同一个进程中来区分的(这里仅以activity和service通信为例来说明,其他场景原理类似)。①如果是在同一进程,那么这个代理对象mServiceProxy其实就是mService对象。②而当它们不在同一个进程中时,mServiceProxy和mService就属于不同进程空间中的对象,由于不同进程之间的数据不能直接访问,所以这个时候binder driver就来充当一个中间桥梁的作用,来完成参数和返回结果等数据的传递(其实也就是在Linux内核空间开辟了一段共享内存),从而实现通信的目的。当然为了方便开发者使用binder,Android对binder的使用进行了一定的封装,提供了一个AIDL。通过AIDL我们就只需关心service提供的功能接口,而不用去关心这些接口调用的具体细节。
四、onRebind
在多次调用bindService和unbindService时会调用到该接口,一般不会在这do something,不过可能会有一些数据统计放在这里以观察用户的某一操作行为。
五、onUnbind
一般在Activity与Service断开连接时,调用UnbindService方法时调用。该接口默认返回false,如果要在onRebind中do something,需要使其返回true。
六、onDestroy
在Service销毁并释放onCreate中申请的资源时调用,参考IntentService实现:
@Override
public void onDestroy() {
mServiceLooper.quit();
}
一般可以通过stopService或者unbindService(!通过startService启动Service)方式来销毁不再需要的Service。
Service VS 线程池
Android提供Service处理后台任务,但有的时候会实现一套线程池机制或者使用Android提供的AsyncTask来执行后台任务。
- Service是Android系统提供的用来处理后台任务的组件,创建进程方便、使用方便、优先级高,可做一定程度的保活。但是多次IPC带来的效率不高问题也同样使人头大。
- 线程池的运行效率高,配置和使用灵活。但是多进程实现不方便, 由于Android实现了一套进程托管机制,我们不能直接创建一个新的进程,而只能通过四大组件的形式创建新的进程。