Android四大组件——Service
Service是可以长时间运行在后台的没有用户界面的组件(区别于Activity),运行与UI线程中(区别与Thread)。
1、Service的两种启动方式
(1)startService()
创建服务类继承于Service,onBind()方法默认返回null就行;
在AndroidManifest文件中配置Service组件;
指定Intent并通过Context.startService(intent)方法启动Service服务;
在需要停止服务的时候通过Context.stopService(intent);
(2)bindService()
创建BindService服务端继承于Service,创建一个实现IBinder接口的实例对象并提供公共方法给客户端调用;
在服务端中必须实现onBind()回调方法并返回创建的Binder对象实例;
在客户端中实现,从onServiceConnected(ComponentName name, IBinder binder)回调方法中获取Service端Binder实例,并使用提供的方法调用服务端Service;
client通过bindService (Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;
当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnection sc);
2、Service的生命周期
(1)通过startService方式启动
首次调用startService()时,依次回调 onCreate()、onStartCommand();
再次调用startService()时,将只执行onStartCommand(),因为此时Service已经创建了,无需执行onCreate()回调。
调用stopService()或者stopSelf()时,回调onDestroy();
PS:所以无论多少次调用startService,每个服务都只存在一个实例,只需要一次stopService()或stopSelf()即可将此Service终止,然后执行onDestroy()函数。
与client调用组件的关系(Activity):通过startService方式启动的服务的生命周期与Activity的生命周期没有任何关系,Activity如果销毁了也不会杀死Service,只有当Activity调用stopService或者Service本身调用stopSelf()才能停止此服务。(系统内存不足时也会kill掉Service)
(2)通过bindService方式启动
首次进行bindService()绑定时,依次回调onCreate()、onBind()、onServiceConnected();
再次进行bindService()绑定时,没有触发回调;
调用unBindService()进行解绑时,依次回调onUnBind()、onDestroy();
与client调用组件的关系(Activity):通过bindService方式启动的服务的生命周期与Activity的生命周期有关系,只有当Activity被销毁了或者调用Context.unbindService才能停止Service服务,否则将一直在后台运行。(系统内存不足时也会kill掉Service)
3、Service与Activity的通信方式
(1)startService方式启动
当通过startService(Intent intent)方式启动的Service,Activity可以把Intent参数传递给Service,如果此时Service需要把Intent参数传递给Activity,只能通过发送广播的形式(Activity需要注册广播)
(2)bindService方式启动
可以通过Binder对象(统一进程)或者Messenger信使(跨进程)进行通信。
PS:关于onBind()的说明:onBind()是Service类中唯一的抽象方法,必须由子类实现,其返回值只对通过bindService方式启动的Service才有用,在startService方式中默认返回null就行。
PS:onStartCommand(Intent intent, int flags, int startId)的参数说明:flags参数默认下为0,可以指定以下常量:
START_NOT_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中Client明确再次调用startService()启动此Service。
START_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand()方法,但其中的Intent将是null。
START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(...)方法时,其中的Intent将是非空,将是最后一次调用startService(...)中的intent。
PS:只有调用stopService才会回调onDestroy()方法。只有调用unbindService()才会回调onDestroy()方法。
PS:在bindService启动方式中,客户端的onServiceDisconnected()不会在onUnBind()执行后回调,只有放系统异常杀死Service时才会进行回调。
PS:BroadcastReceiver组件不能作为bindService()的client,因为BroadcastReceiver的生命周期很短,当执行完onReceive()回调时,BroadcastReceiver生命周期已经完结。而bindService又与Client本身的生命周期相关,因此Android中不允许BroadcastReceiver去bindService()。
补充:
因为Service运行在主线程,所以如果想要在Service执行耗时操作,必须创建子线程来执行耗时任务,但是由于Service服务需要手动调用stopService()去停止服务,操作起来比较麻烦,所以系统提供了IntentService来解决这个问题。IntentService继承于Service,同时封装了Handler和HandlerThread,重写onHandlerIntent()方法并在其中执行耗时任务即可,并且任务执行完毕后会自动调用stopSelf()停止服务,适用于完成一些短期的耗时任务。