Service总结

转载博客:http://blog.csdn.net/vanpersie_9987

ServiceAndroid中一个类,它是Android四大组件之一,使用Service可以在后台执行长时间的操作( perform long-running operations in the background ),Service并不与用户产生UI交互。其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行。一个组件可以与Service绑定并与之交互,甚至是跨进程通信(IPC)。例如,一个Service可以在后台执行网络请求、播放音乐、执行文件读写操作或者与 content provider交互 等。


本文将介绍Services的定义、创建、启动、绑定、前台Service等相关内容,如需访问官方原文,您可以点击这个链接:《Services》

Services

Services有两种启动形式:

  • Started:其他组件调用startService()方法启动一个Service。一旦启动,Service将一直运行在后台(run in the background indefinitely)即便启动Service的组件已被destroy。通常,一个被start的Service会在后台执行单独的操作,也并不给启动它的组件返回结果。比如说,一个start的Service执行在后台下载或上传一个文件的操作,完成之后,Service应自己停止。

  • Bound:其他组件调用bindService()方法绑定一个Service。通过绑定方式启动的Service是一个client-server结构,该Service可以与绑定它的组件进行交互。一个bound service仅在有组件与其绑定时才会运行(A bound service runs only as long as another application component is bound to it),多个组件可与一个service绑定,service不再与任何组件绑定时,该service会被destroy。

当然,service也可以同时在上述两种方式下运行。这涉及到Service中两个回调方法的执行:onStartCommand()(通过start方式启动一个service时回调的方法)、onBind()(通过bind方式启动一个service回调的方法)。


无论通过那种方式启动service(start、bind、start&bind),任何组件(甚至其他应用的组件)都可以使用service。并通过Intent传递参数。当然,您也可以将Service在manifest文件中配置成私有的,不允许其他应用访问。

!请注意:Service运行在主线程中(A service runs in the main thread of its hosting process),Service并不是一个新的线程,也不是新的进程。也就是说,若您需要在Service中执行较为耗时的操作(如播放音乐、执行网络请求等),需要在Service中创建一个新的线程。这可以防止ANR的发生,同时主线程可以执行正常的UI操作。


使用Service还是使用Thread?

Service是一个运行在后台的组件,并不与用户交互。您仅在需要的时候创建Service( create a service only if that is what you need)。 
当用户正在与UI交互时,需要执行一些主线程无法完成的工作,应当创建一个线程。例如当activity正在运行时,需要播放音乐,此时需要在Activity的onCreate()中创建线程并在onStart()中开启。最后在onStop()中停止。您也可以考虑使用AsyncTask 或 HandlerThread来替代Thread创建线程。

Service基础(The Basics)

为了创建Service,需要继承Service类。并重写它的回调方法,这些回调方法反应了Service的生命周期,并提供了绑定Service的机制。最重要的Service的生命周期回调方法如下所示:

  • onStartCommand():当其他组件调用startService()方法请求启动Service时,该方法被回调。一旦Service启动,它会在后台独立运行。当Service执行完以后,需调用stopSelf() 或 stopService()方法停止Service。(若您只希望bind Service,则无需调用这些方法)

  • onBind():当其他组件调用bindService()方法请求绑定Service时,该方法被回调。该方法返回一个IBinder接口,该接口是Service与绑定的组件进行交互的桥梁。若Service未绑定其他组件,该方法应返回null。

  • onCreate():当Service第一次创建时,回调该方法。该方法只被回调一次,并在onStartCommand() 或 onBind()方法被回调之前执行。若Service处于运行状态,该方法不会回调。

  • onDestroy():当Service被销毁时回调,在该方法中应清除一些占用的资源,如停止线程、接触绑定注册的监听器或broadcast receiver 等。该方法是Service中的最后一个回调。

如果某个组件通过调用startService()启动了Service(系统会回调onStartCommand()方法),那么直到在Service中手动调用stopSelf()方法、或在其他组件中手动调用stopService()方法,该Service才会停止。

如果某个组件通过调用bindService()绑定了Service(系统不会回调onStartCommand()方法),只要该组件与Service处于绑定状态,Service就会一直运行,当Service不再与组件绑定时,该Service将被destroy。

当系统内存低时,系统将强制停止Service的运行;若Service绑定了正在与用户交互的activity,那么该Service将不大可能被系统kill( less likely to be killed)。如果创建的是前台Service,那么该Service几乎不会被kill(almost never be killed)。否则,当创建了一个长时间在后台运行的Service后,系统会降低该Service在后台任务栈中的级别——这意味着它容易被kill(lower its position in the list of background tasks over time and the service will become highly susceptible to killing),所以在开发Service时,需要使Service变得容易被restart,因为一旦Service被kill,再restart它需要其资源可用时才行(restarts it as soon as resources become available again ),当然这也取决于onStartCommand()方法返回的值,这将在后续介绍。

在manifest文件中注册service(Declaring a service in the manifest)

在manifest文件中注册service的方式如下:


除此之外,在<service>标签中还可以配置其他属性,比如,需要启动该service所需的权限、该service应运行在哪个进程中 等( permissions required to start the service and the process in which the service should run)。android:name属性是唯一不可缺省的,它指定了Service的全限定类名。一旦发布了应用,该类名将不可更改。

!请注意:为了保证应用的安全,请使用显式Intent启动或绑定一个Service,请不要在<service>标签中配置intent-filter。

若不确定该启动哪个Service,那么可以在<service>中配置intent-filter,并在Intent中排除该Service(supply intent filters for your services and exclude the component name from the Intent),但必须调用Intent的setPackage()方法,来为启动的service消除歧义(provides sufficient disambiguation for the target service)。

注:setPackage()方法传入一个String参数,代表一个包名。该方法表示该Intent对象只能在传入的这个包名下寻找符合条件的组件,若传入null,则表示可以在任意包下寻找。

android:exported属性设为false,表示不允许其他应用程序启动本应用的组件,即便是显式Intent也不行(even when using an explicit intent)。这可以防止其他应用程序启动您的service组件。

使用start方式启动Service(Creating a Started Service)

其他组件调用 startService()方法可以启动一个Service,接着,Service会回调 onStartCommand()生命周期方法。 startService()方法中传入一个Intent参数,用于显式指定目标Service的名字,并携带data以供Service使用,该Intent参数将回传至 onStartCommand()方法中。 
比如说,Activity需要向在线 数据库中上传数据,那么可以调用 startService()启动一个Service,并将数据传入Intent的data中,接着, onStartCommand()方法会接收这个Intent并开启一个线程将数据上传至网络,当数据上传完成后,该Service将停止并被destroy。

一般使用如下两种方式创建一个start Service:

  • 继承Service类:请务必在Service中开启线程来执行耗时操作,因为Service运行在主线程中。

  • 继承IntentService类IntentService继承于Service,若Service不需要同时处理多个请求,那么使用IntentService将是最好选择:您只需要重写onHandleIntent()方法,该方法接收一个回传的Intent参数,您可以在方法内进行耗时操作,因为它默认开启了一个子线程,操作执行完成后也无需手动调用stopSelf()方法,onHandleIntent()会自动调用该方法。

继承IntentService类(Extending the IntentService class)

在大多数情况下,start Service并不会同时处理多个请求(don’t need to handle multiple requests simultaneously),因为处理多线程较为危险(a dangerous multi-threading scenario),所以继承 IntentService类带创建Service是个不错选择。

使用IntentService的要点如下:

  • 默认在子线程中处理回传到onStartCommand()方法中的Intent;

  • 在重写的onHandleIntent()方法中处理按时间排序的Intent队列,所以不用担心多线程(multi-threading)带来的问题。

  • 当所有请求处理完成后,自动停止service,无需手动调用stopSelf()方法;

  • 默认实现了onBind()方法,并返回null;

  • 默认实现了onStartCommand()方法,并将回传的Intent以序列的形式发送给onHandleIntent(),您只需重写该方法并处理Intent即可。

综上所述,您只需重写 onHandleIntent()方法即可,当然,还需要创建一个构造方法,示例如下:


如果您还希望在IntentService的 继承类中重写其他生命周期方法,如onCreate()、onStartCommand() 或 onDestroy(),那么请先调用各自的父类方法以保证子线程能够正常启动。

比如,要实现onStartCommand()方法,需返回其父类方法:


如果您还希望在IntentService的 继承类中重写其他生命周期方法,如onCreate()、onStartCommand() 或 onDestroy(),那么请先调用各自的父类方法以保证子线程能够正常启动。

比如,要实现onStartCommand()方法,需返回其父类方法:

onHandleIntent()外,onBind()方法也无需调用其父类方法。

继承Service类(Extending the Service class)

如果您需要在Service中执行多线程而不是处理一个请求队列(perform multi-threading instead of processing start requests through a work queue),那么需要继承Service类,分别处理每个Intent。

在Service中执行操作时,处理每个请求都需要开启一个线程,并且同一时刻一个线程只能处理一个请求( for each start request, it uses a worker thread to perform the job and processes only one request at a time)。




注意到onStartCommand()返回一个整形变量,该变量必须是下列常量之一:

  • START_NOT_STICKY:若执行完onStartCommand()方法后,系统就kill了service,不要再重新创建service,除非系统回传了一个pending intent。这避免了在不必要的时候运行service,您的应用也可以restart任何未完成的操作。
  • START_STICKY:若系统在onStartCommand()执行并返回后kill了service,那么service会被recreate并回调onStartCommand()。dangerous不要重新传递最后一个Intent(do not redeliver the last intent)。相反,系统回调onStartCommand()时回传一个空的Intent,除非有 pending intents传递,否则Intent将为null。该模式适合做一些类似播放音乐的操作。
  • START_REDELIVER_INTENT:若系统在onStartCommand()执行并返回后kill了service,那么service会被recreate并回调onStartCommand()并将最后一个Intent回传至该方法。任何 pending intents都会被轮流传递。该模式适合做一些类似下载文件的操作。

启动服务(Starting a Service)


startService(intent)方法将立即返回,并回调onStartCommand()(请不要手动调用该方法),若该Service未处于运行状态,系统将首先回调onCreate(),接着再回调onStartCommand()。若您希望Service可以返回结果,那么需要通过调用getBroadcast 返回的PendingIntent启动Service(将PendingIntent包装为Intent),service可使用broadcast 传递结果。


多个启动Service的请求可能导致onStartCommand()多次调用,但只需调用stopSelf() 、 stopService()这两个方法之一,就可停止该服务。

停止服务(Stopping a service)

一个启动的Service必须管理自己的生命周期。系统不会主动stop或destroy一个运行的Service,除非系统内存紧张,否则,执行完onStartCommand()方法后,Service依然运行。停止Service必须手动调用stopSelf()(在Service中)或调用stopService()(在启动组件中)







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Android开发中,Service是一个非常重要的组件,用于在后台执行长时间运行的操作,不与用户交互。以下是本次实验的总结: 1. Service生命周期 Service的生命周期包括:onCreate()、onStartCommand()、onBind()、onUnbind()、onRebind()和onDestroy()。开发者可以根据不同的业务需求实现这些生命周期函数。 2. Service的启动和停止 Service的启动和停止有两种方式:使用startService()和stopService()方法来启动和停止Service;使用bindService()和unbindService()方法来绑定和解绑Service。需要注意的是,使用startService()方法启动的Service会一直运行,直到调用stopService()方法或者Service自己调用stopSelf()方法;使用bindService()方法启动的Service会在与之绑定的Activity销毁时自动停止。 3. Service的通信 Service可以和Activity之间进行通信,可以使用Intent传递数据,也可以使用Messenger进行通信。如果需要在Service中执行耗时操作,需要在Service中开启一个新的线程来执行,否则会阻塞主线程。 4. Service的注册 在AndroidManifest.xml文件中注册Service,可以使用以下代码: ``` <service android:name=".MyService" /> ``` 5. Service的注意事项 在使用Service时,需要注意以下几点: - Service是在主线程中运行的,不能在Service中执行耗时操作,否则会阻塞主线程。 - Service一旦启动就会一直运行,需要在适当的时候停止Service。 - Service可以和Activity之间进行通信,需要根据具体的业务需求选择合适的通信方式。 总之,Service是Android开发中非常重要的组件,掌握其使用方法和生命周期函数对于开发高质量的Android应用程序非常有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值