一、Service简介
Service 是Android四大组件之一,是一种可以执行长时间操作而不提供界面的应用组件。Service 启动后,当用户切换到其他应用时,其依然可在后台继续运行。此外,组件也可以绑定到 Service 并与之进行交互,甚至是执行进程间通信(IPC)。主要是用来处理一些用户无感知的耗时后台操作,如:网络数据处理、播放音乐、定位信息、执行文件IO操作、数据库读写操作等。
二、创建Service
创建一个 Service 非常简单,只需继承 Service 或其子类即可,以下是一个具体示例:
1 | public class HelloService extends Service { |
上面的 HelloService 继承自 Service,并实现了其生命周期方法。其中 onCreate() 和 onDestroy() 同 Activity 的生命周期方法一样,在service创建或销毁时会被系统调用的;onStartCommand() 和 onBind() 方法也属于 Service 的生命周期方法,但是其根据启动方式不同而被回调的方法不同,本例中只关注 onStartCommand() 方法(后续我们在探索service的两种启动方式时再详细说明 onBind() 的使用),当service是以非绑定的方式启动时,在回调完onCreate()方法后,会立即回调onStartCommand()方法,并将附带参数以Intent的方式传递进来,service的重要工作也是在这个方法中实现的。
Service 同 Activity 一样也必须在AndroidManifest中声明,之后才能使用,以下为HelloService的清单声明示例:1
2
3
4<service
android:name=".service.HelloService"
android:description="@string/service_des"
android:exported="false" />
其中name是必须配置的,其他的根据自己的需要选择性配置,以下是service可配置的所有属性,各个属性的功能及取值说明请参考Service清单配置说明:
1 | <service android:description="string resource" |
创建完HelloService并在清单文件中声明后,我们就可以启动service了。你可以在Activity和ContentProvider中通过Intent来启动服务,如下所示:
1 | Intent intent = new Intent(context, HelloService.class); |
运行结果如下:
1 | I/HelloService: HelloService onCreate |
注意:为了确保应用的安全性,请始终使用显示Intent启动服务,且不要为Service声明intent_filter。从Android5.0(API 21)开始,通过隐式Intent调用bindService会抛出系统异常
至此我们的service就启动起来了。service启动后,其生命周期即独立于启动的组件了,即使系统已经销毁启动服务的组件,该服务依然可在后台无限期地运行。因此,当任务完成后应该主动调用并停止服务,可由其他组件在外部调用 stopService() 或在服务内部调用 stopSelf() 方法来停止服务,详细的使用方式我们会在接下来的文章中分析。
默认情况下,服务与服务声明所在的应用运行于同一进程,并且运行在该应用的主线程中。如果在服务内部要执行密集型或阻塞性操作,会降低该应用Activity的性能,同时还有可能引起ANR(服务内任务一般在20s执行不完就会ANR)。因此,如果是密集型或阻塞性操作,请在服务内启动新线程来执行对应任务(IntentService默认封装了工作线程,可直接继承IntentService,将任务放到其工作线程中执行)。总结下使用service的大致流程:
- 继承Service或其子类(IntentService),并实现其生命周期方法,编写任务处理代码;
- 在清单文件中声明Service;
- 在其他组件中启动Service;
三、继承IntentService类
通常情况下服务无需同时处理多个请求(实际上,这种多线程操作服务也是危险的),Android提供了一种单一线程并顺序执行任务的Service子类IntentService,其具有以下特点:
- 在其内部创建了默认的工作线程,用来处理外部传递给 onStartCommand() 的所有Intent。
- 内部维护了工作队列,用于将Intent逐一传递给 onHandleIntent() 方法,避免多线程同步问题。
- 在处理完所有的任务后,自动停止服务,不需要你关心何时停止的问题。
- 默认实现了 onStartCommand() 方法,并将其接收到的Intent依次发送到工作队列和 onHandleIntent() 处理。
- 默认实现了 onBind() 方法(返回null),也就是外部通过 bindService() 方法启动服务是无效的,只能通过 startService() 启动服务。
以下是继承IntentService的示例:
1 | public class HelloIntentService extends IntentService { |
如上例所示,我们只需要继承IntentService并实现 onHandleIntent() 方法即可,将你要处理的任务放到 onHandleIntent() 方法中,IntentService就会逐个处理传递进来的任务。我们在外部用一个线程池来模拟多线程启动服务的情况,并查看下HelloIntentService是如何处理任务的,示例代码如下:
1 | private void testIntentService() { |
运行结果如下:
1 | 11-08 09:16:37.150 7749 7829 I HelloIntentService: thread name:IntentService[HelloIntentService] |
可以看出任务大约每隔1s执行一次,所有任务都执行完后service也就停止了。
注意:如果你还要重写其他回调方法,如:onCreate()、onStartCommand()或onDestroy(),必须确保调用super实现,以保证 IntentService 能正确处理工作线程的生命周期。四、总结
Service 作为Android四大组件之一,具有生命周期独立于启动组件而在后台不断运行的特性,主要用来处理一些用户无感知的耗时操作。通过创建服务、清单文件中声明服务、在其他组件中启动服务三个步骤来完成服务的使用,并可由外部组件手动停止服务,也可以在自身内部将服务停止。
如果你的任务需要另开线程处理,且不需要多线程处理,应首选继承 IntentService 实现你的服务,其内置工作线程处理任务,并无需你关心其生命周期。