美文网首页android
Service-服务(一)生命周期及使用方式

Service-服务(一)生命周期及使用方式

作者: 林锦洲 | 来源:发表于2019-01-23 15:40 被阅读37次

    一、Service(服务)概述

    • Service是Android系统中的四大组件之一。
    • Service是可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响,除非系统必须回收内存资源,否则系统不会停止或销毁Service
    • 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
    • Service默认并不会运行在子线程中,Service是在主线程里执行操作的,因此,不要在Service中执行耗时的操作,避免因为执行耗时操作而导致ANR,除非你在Service中创建了子线程来完成耗时操作。

    二、两种启动方式

    服务基本上分为两种形式:

    • startService
      当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“start”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。 操作完成后,服务会自行停止运行。
    • bindService
      当应用组件通过调用 bindService() 绑定到服务时,服务即处于“bind”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

    虽然上文是分开概括讨论这两种服务,但是您的服务可以同时以这两种方式运行,也就是说,它既可以是start服务(以无限期运行),也允许bind。问题只是在于您是否实现了一组回调方法:onStartCommand()(允许组件启动服务)和 onBind()(允许绑定服务)。
    无论应用是处于启动状态还是绑定状态,抑或处于启动并且绑定状态,任何应用组件均可像使用Activity 那样通过调用 Intent 来使用服务(即使此服务来自另一应用)。 不过,可以通过AndroidManifest.xml将服务声明为私有服务,并阻止其他应用访问。

    三、生命周期

    Service生命周期。左图显示了使用 startService() 所创建的服务的生命周期,右图显示了使用 bindService() 所创建的服务的生命周期。

    Service生命周期

    四、使用Service的步骤

    1.定义一个类继承Service(或使用它的一个现有子类如IntentService
    2.在Manifest.xml文件中配置该Service
    3.使用startService()bindService()方法启动该Service
    4.不再使用时,调用stopService()stopSelf()unbindService()方法停止该服务

    4.1定义一个类继承Service

    public class MService extends Service {  
        /**
        * 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。
        * 如果服务已在运行,则不会调用此方法。该方法只被调用一次
        */
        @Override  
        public void onCreate() {  
            super.onCreate();  
        }  
        /**
        * 每次通过startService()方法启动Service时都会被回调。
        */
        @Override  
        public int onStartCommand(Intent intent, int flags, int startId) {  
            return super.onStartCommand(intent, flags, startId);
        }  
        /**
        * 服务销毁时的回调
        */
        @Override  
        public void onDestroy() {  
            super.onDestroy();  
        }  
        /**
        * 绑定服务时才会调用 必须要实现的方法 
        */
        @Override  
        public IBinder onBind(Intent intent) {  
            return null;  
        }  
      
    }  
    

    虽然这个Service什么都没干,但实际上它是Service组件的框架,如果希望Service组件做某些事情,那么只要在onCreate()onStartCommand()方法中定义相关业务代码即可

    4.2在清单文件声明

    定义了上面的Service之后,接下来需要在Androidmaniferst.xml文件中配置该Service,配置Service使用<service../>元素。与配置Activity显示的是,配置Service时也可为<service../>元素配置<intent-filter.../>子元素,用于说明该Service可被那些Intent启动。

    <application
            ...
            <service android:name=".MService" >
                <intent-filter>
                    <action android:name="..." />
                </intent-filter>
            <service/>
    </application>
    

    Service包含的属性有

    <service android:enabled=["true" | "false"]
        android:exported=["true" | "false"]
        android:icon="drawable resource"
        android:isolatedProcess=["true" | "false"]
        android:label="string resource"
        android:name="string"
        android:permission="string"
        android:process="string" >
        . . .
    </service>
    
    属性 说明
    description 对服务进行描述,属性值应为对字符串资源的引用,以便进行本地化
    directBootAware 设置是否可以在用户解锁设备之前运行,默认值为“false”
    enabled 设置是否可以由系统来实例化服务。< application >元素有自己的enabled属性,适用于包括服务在内的所有应用程序组件。要启用服务,< application >和< service >属性必须都为“true”(默认情况下都为true)。如果其中一个是“false”,则服务被禁用
    exported 设置其他应用程序的组件是否可以调用本服务或与其交互,如果可以,则为“true”。当值为“false”时,只有同一个应用程序或具有相同用户ID的应用程序的组件可以启动该服务或绑定到该服务。该属性的默认值取决于服务是否包含Intent filters。没有任何过滤器意味着它只能通过指定其确切的类名来调用,这意味着该服务仅用于应用程序内部使用(因为其他人不知道类名)。所以在这种情况下,默认值为“false”。 另一方面,如果存在至少一个过滤器,意味着该服务打算供外部使用,因此默认值为“true”
    icon 服务的图标,属性值应是对drawable资源的引用。如果未设置,则将使用应用程序图标
    isolatedProcess 设置该服务是否作为一个单独的进程运行,如果设置为true,此服务将在与系统其余部分隔离的特殊进程下运行,并且没有自己的权限,与它唯一的通信是通过服务API(绑定和启动)
    label 可以向用户显示的服务的名称,属性值应是对字符串资源的引用
    name 服务类的完全限定名
    permission 设定组件必须具有的权限,得以启动服务或绑定服务。如果startService(),bindService()或stopService()的调用者没有被授予此权限,则该方法将不会工作,并且Intent对象不会传递到服务中
    process 用来运行服务的进程的名称。通常,应用程序的所有组件都运行在应用程序创建的默认进程中,它与应用程序包名具有相同的名称。 < application >元素的process属性可以为所有组件设置不同的默认值,但组件可以使用自己的进程属性覆盖默认值,从而允许跨多个进程扩展应用程序

    4.3启动和停止Service

    通过将 Intent(指定要启动的服务)传递给 startService(),从 Activity 或其他应用组件启动服务。Android 系统调用服务的 onStartCommand() 方法,并向其传递 Intent

    Intent intent = new Intent(this, MService.class);
    startService(intent);
    
    • 第一次调用startService()方法时,onCreate()方法、onStartCommand()方法将依次被调用,而多次调用startService()时,只有onStartCommand()方法被调用。
    • 启动服务必须管理自己的生命周期。也就是说,除非系统必须回收内存资源,否则系统不会停止或销毁服务,而且服务在onStartCommand() 返回后会继续运行。因此,服务必须通过调用 stopSelf() 自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。
    • 一旦请求使用 stopSelf()stopService() 停止服务,系统就会尽快销毁服务。
    • 但是,如果服务同时处理多个 onStartCommand() 请求,则您不应在处理完一个启动请求之后停止服务,因为您可能已经收到了新的启动请求(在第一个请求结束时停止服务会终止第二个请求)。为了避免这一问题,您可以使用stopSelf(int) 确保服务停止请求始终基于最近的启动请求。也就说,在调用 stopSelf(int) 时,传递与停止请求的 ID 对应的启动请求的 ID(传递给 onStartCommand()startId)。然后,如果在您能够调用 stopSelf(int) 之前服务收到了新的启动请求,ID 就不匹配,服务也就不会停止。

    注意:为了避免浪费系统资源和消耗电池电量,应用必须在工作完成之后停止其服务。 如有必要,其他组件可以通过调用stopService() 来停止服务。即使为服务启用了绑定,一旦服务收到对 onStartCommand() 的调用,您始终仍须亲自停止服务。

    4.4绑定Service并与之通讯

    待续。。。

    相关文章

      网友评论

        本文标题:Service-服务(一)生命周期及使用方式

        本文链接:https://www.haomeiwen.com/subject/lwdjjqtx.html