【Android】【笔记】《Android 入门经典》part 14 Service

来源:互联网 发布:宾馆软件破解版 编辑:程序博客网 时间:2024/06/02 11:38
本文为个人读书笔记,大部分为书中内容摘要。仅供记录和分享学习中遇到的需要留意的问题,如有相关版权问题请及时通知作者。

Service概述
     Service 服务 是能够在后台长时间运行操作并且不提供用户界面的应用程序组件。其他应用程序组件能启动服务并且不受用户程序切换的影响。组件能够绑定到服务与之交互,甚至执行进程间通信(IPC)。

Sevice的分类
     从本质上分为两种类型:
     Started 启动:当应用程序组件通过调用startService()方法启动服务时,服务处于started状态。一旦启动,服务能在后台无限期运行,即使启动它的组件已经被销毁。通常,启动服务之星单个操作并且不会向调用者返回结果。
     Bound 绑定:当应用程序组件通过调用bindService()方法绑定到服务时,服务器处于bound状态。绑定服务提供客户端-服务器接口以允许组件与服务交互发送请求、获得结果甚至使用进程间通信IPC跨进程完成这些操作。仅当其他应用程序组件与之绑定时,绑定服务才运行。多个组件可以一次不绑定到一个服务上,但是当它们都解绑定时,服务被销毁。
     服务可以同时属于两种类型。重点在于是否实现一些回调方法:onStartCommand()方法允许组件启动服务,onBind()方法允许组件绑定服务。
     不管应用程序是否为启动状态 、绑定状态或者两者,都能通过Intent使用服务,就像使用Activity一样。开发人员可以在配置文件中将服务声明为私有的,从而阻止其他应用程序访问。
     服务运行于管理它的进程的主线程,服务不会创建自己的线程也不会运行与独立的进程。这意味着,如果服务将完成CPU秘籍工作或者阻塞操作,开发人员需要在服务中创建新的线程来完成这些工作。通过使用独立的线程,能够减少应用程序不响应 ANR错误的风险并且应用程序主线程仍然能用于用户与Activity交互。
     
Service类中重要方法
     为了创建服务,需要创建Service类的子类。在实现类中,需要重写一些处理生命周期重要方面的回调方法并根据需要提供组件绑定到服务的机制。
     1、onStartCommand()
     当其他组件调用startService()方法请求服务启动时,系统调用该方法。一旦该方法执行,服务就启动处于started状态并在后台无限制运行。如果实现该方法,则需要在任务完成时调用stopSelf()或stopService()方法停止服务。
     2、onBind()
     当其他组件调用bindService()方法想与服务绑定时,系统调用该方法。在该方法的实现中,开发人员必须通过返回IBinder提供客户端用来与服务通信的接口。该方法必须实现,但是如果不想允许绑定,则应该返回null;
     3、onCreate()
     当服务第一次创建时,系统调用该方法执行一次性简历过程。如果服务已经运行,该方法不被调用。
     4、onDestroy()
     当服务不再使用并即将销毁时,系统调用该方法。服务应该实现该方法来清理诸如线程、注册监听器、接收者等资源。这是服务受到的最后调用。
     如果组件调用startService()方法启动服务,服务需要使用stopSelf()方法停止自身,或者其他组件使用stopService()方法停止该服务。
     如果组件调用bindService()方法创建服务,服务运行时间与组件绑定到服务的时间一样长。一旦服务从所有客户端解绑定,系统会将其销毁。
     Android 系统仅 当系统内存不足并且必须回收系统资源来显示用户关注的Activity时,才会强制停止服务。如果服务绑定到用户关注的Activity,则会降低停止频率。如果服务被声明为前台运行,则基本不会停止。否则,如果服务时started状态并且长时间运行,则系统会随时间推移降低其在后台任务列表中的位置并且服务有很大的概率被停止。如果服务时started状态,则必须设计如何优雅的重启服务。如果系统停止服务,则资源可用时就会重启它。

Service的声明
     需要向<application>标签中增加<service>子标签
     该标签的属性:
     1、android:enabled   
      服务能否被系统实例化,默认true 可以,false不可以。application也有enabled属性,application和service属性必须同时设置成true,才能让服务可用。
     2、android:exported 
     其他应用程序组件能否调用服务或者与其交互,true可以,false不可以。false的时候只有同一个应用程序的组件或者具有相同用户id的应用程序能启动或者绑定到服务
     默认值依赖于服务是否包含Intent过滤器。没有过滤器说明着它仅能通过精确类名调用。这意味着服务仅用于应用程序内部。此时默认值为false。存在至少一个过滤器暗示服务可以于外部使用,则默认值为true
     该属性不是限制其他应用程序使用服务的唯一方式。还可以使用Permission属性限制外部服务实体与服务交互
     3、android:icon
     服务的图表。该属性必须设置成包含图片定义的可绘制资源引用,如果没有设置,使用应用程序图表取代。
     服务图标,不管在此设置还是在<application>中设置,都是所有服务的Intent过滤器默认图标
     4、android:label
     显示给用户的服务名称。如果没有设置,使用应用程序标签取代。
     服务标签,不管在此设置还是在<application>标签设置,都是所有服务的Intent过滤器默认图标。
     表卡应该设置为字符串资源引用,这样它能像用户界面的其他字符串那样benndi。
     5、android:name
     实现服务的Service子类名称。这应该是一个完整的类名,包含包名。为了简便,如果名称的第一个符号是点号,它会增加在<manifest>标签中定义的包名。
     一旦发布了应用程序,不应该再修改这个名称。它没有默认值并且必须指定。
     6、android:permission
     实体必须包含的权限名称,以便启动或者绑定到服务。如果startService()、BingService()或stopService()方法调用者没有被授权,方法调用无效并且Intent对象也不会发送给服务。
     如果该属性没有设置,使用<application>标签的permission属性设置给服务。如果都没设置,服务不受权限保护。
     7、android:process
     服务运行的进程名称。通常,应用程序的全部组件运行于为应用程序创建的默认进程。它与应用程序包名相同。<applicaion>标签的的process属性能为全部组件设置一个不同的默认值。但是组件能用自己的process属性重写默认值,从而允许应用程序跨越多个进程。
     如果分配给该属性的名称以冒号开头,仅属于应用程序的新进程会在需要时创建,服务能在该进程中运行。如果进程名称以小写字母开头,服务会运行在以此为名的全局进程,但需要提供相应的权限。者允许不同应用程序组件共享进程,减少资源使用。



Started Service的使用
     Started Service 启动服务 是由其他组件调用startService()方法启动的,这导致服务的onStartCommand()方法被调用。
     当服务是“started”状态时,它的声明周期与启动它的组件无关并且可以在宏图爱无限期运行。及时启动服务的组件已经销毁。因此,服务需要在完成任务后调用stopSelf()停止,或者由其他族健脑调用stopService()方法停止。
     应用程序组件能通过调用startService()方法和传递Intent对象来启动服务,在Intent对象中指定了服务并且包含服务需要使用的全部数据。服务使用onStartCommand()方法接收Intent。
     Android提供了两个类供开发人员继承来创建启动服务:
     Service:这是所有服务的基类。当继承该类时,创建新线程来执行服务的全部工作是非常重要的。因为服务默认使用应用程序主线程,这可能降低应用程序Activity的运行性能。
     IntentService:Service类的子类,每次使用一个工作线程来吹全部启动请求。在不必同时处理多个请求时,这是最佳选择。开发人员仅需事先onHandleIntent()方法,它接收每次启动请求的Intent以便完成后台任务。

继承IntentService类
     IntentService完成的任务:
     1、创建区别于应用程序需主线程的默认工作线程来执行发送到onStartCommand()方法的全部Intent。
     2、创建工作队列每次传递一个Intent到onHandleIntent()方法实现,这样就不必担心多线程
     3、所有启动请求处理完毕后停止服务,这样就不必调用stopSelf()方法
     4、提供onBind方法默认实现,其返回值是null
     5、提供onStartCommand()方法默认实现,它先发送Intent到工作队列然后到onHandleIntent()方法实现。
     所有这些加载一起说明开发人员仅需要实现onHandleIntent()方法来完成客户端提供的任务。由于IntentService类没有提供空参数的构造方法,因此需要提供一个构造方法。
     实现IntentService类所必须的全部操作就是:没有参数的构造方法和onHandleIntent()方法。
     如果开发人员决定也重写其他毁掉方法:onCreate()、onStartCommand()或onDestroy(),需要调用父类实现,这样IntentService能正确处理工作线程的生命周期。
     除了onHandleIntent()方法,仅有onBind()方法不必调用父类实现,该方法在服务允许绑定时实现。

继承Service类
     如果需要让服务处理多线程,则可以继承Service类来处理各个Intent。
     onStartCommand()方法必须返回一个整数,该值永爱描述系统停止服务后如何继续服务
onStartCommand()方法返回值的常量值

常量说明START_NOT_STICKY如果系统在onStartCommand()方法返回后停止服务,不重新创建服务,除非有PendingIntent要发送。在避免在不必要时运行服务和应用程序能简单的重启任何未完成工作时,这是最佳选择。START_STICKY如果系统在onStartCommand()方法返回后停止服务,重新创建服务并调用onStartCommand()方法,但是不重新发送最后的Intent。相反,系统使用空Intent调用onStartCommand()方法,除非有PendingIntent来启动服务。此时,这些Intent会被发送。适合多媒体播放器,不执行命令但是无限期运行并等待工作START_REDELIVER_INTENT如果系统在onStartCommand()方法返回后停止服务,重新创建服务并使用发送给服务的最后Intent调用onStartCommand()方法。全部PendingIntent一次发送。这适合积极执行应该立即回复工作的服务,例如下载文件

启动服务
     可以从Activity或者其他应用程序组件通过传递Intent对象到startService()方法启动服务。Android系统调用服务的onStart()方法并将Intent传递给他。
     不要直接调用onStartCommand()方法。
     startService()方法立即返回,然后Android系统调用服务的onStartCommand()方法。如果服务还没有运行,系统首先调用onCreate()方法,接着调用onStartCommand()方法。
     如果服务没有提供绑定,startService()方法发送的Intent是应用程序组件和服务之间唯一的通讯模式。然而,如果开发人员需要服务返回结果,则启动该服务的客户端能为广播创建PendingIntent并通过启动服务的Intent发送它。服务接下来能使用广播来发送结果。
     多个启动服务的请求导致服务的onStartCommand()方法,然而,仅需要一个停止方法stopSelf()或stopService方法来停止服务。

停止服务
     启动服务必须管理自己的声明周期。即系统不会停止或销毁服务,除非它必须回收系统内存而且在onStartCommand返回后服务继续运行。因此,服务必须调用stopSelf()方法停止自身,或者其他组件调用stopService()方法停止服务。
     当使用stopSelf()或stopService()方法请求停止时,系统会尽快销毁服务。
     然后,如果服务同时处理多个onStartCommand()方法调用请求,则处理完一个请求后,不应该停止服务。因为可能收到一个新的启动请求。为了避免这个问题,可以使用stopSelf(int)方法来确保停止服务的请求总是基于最近受到的启动请求。即当调用stopSelf(int)方法时,同时将启动请求的ID传递给停止请求。这样如果服务在能够调用stopSelf(int)方法前接收到新启动请求,ID会不匹配因而服务不会停止。
     


Bound Service的使用
     绑定服务时允许其他应用程序绑定并且与之交互的Service类实现类。为了提供绑定,开发人员必须实现onBind()回调方法。该方法返回IBinder对象,它定义了客户端用来与服务交互的程序接口。
     客户端通过bindService()方法绑定到服务。此时,客户端必须提供ServiceConnection接口的实现类,它监视客户端与服务之间的连接。bindService()方法立即返回,但是当Android系统创建客户端与服务之间的连接时,它调用serviceConnection接口的onServiceConnected()方法,来发送客户端用来与服务通信的IBinder对象。
     多个客户端与服务解绑定时,系统销毁服务,除非服务也使用startService()方法启动。
     在实现绑定服务时,最重要的是定义onBind()回调方法返回的接口,有3中方式可以定义这个借口。
     1、继承Binder类
     如果服务队应用程序私有并且与客户端运行与相同的进程,则应该继承Binder类来创建接口并且从onBind()方法返回其一个实例。客户端接收Binder对象并使用它来直接访问Binder实现类或者Service类中可用公共方法。
     当服务仅用于私有应用程序时,推荐使用。当服务可以用于其他应用程序或者访问独立进程时,不能使用
     2、使用Messenger
     如果开发人员需要接口跨不同的进程工作,则可以使用Messenger来为服务创建接口。此时,服务定义Handler对象来响应不同类型的Message对象。Handler是Messenger的基础,它能与客户端分享IBinder,允许客户端使用Message对象向服务发送命令。此外,客户端能定义自己的Messenger对象,这样服务能发送回消息。
     这是执行进程间通信IPC的最简单方式,因为Messenger类将所有请求队列化到单独的线程,这样开发人员就不必设计服务为线程安全。
     3、使用AIDL
     AIDL Android接口定义语言执行分解对象到原语的全部工作,以便操作系统能理解并且跨进程执行IPC。使用Messenger创建接口,实际上将AIDL作为底层架构。Messenger在单个线程中将所有客户端请求队列化,这样服务每次收到一个请求。如果开发人员希望服务能同时处理多个请求,则可以直接使用AIDL。此时,服务必须能处理多线程并且要保证线程安全。
     为了直接使用AID,开发人员必须创建定义编程接口的.aidl文件。AndroidSDK工具使用该文件来生成抽象类,它实现接口并处理IPC,然后就可以在服务中使用。
     绝大多数应用程序不应该使用AIDL来创建绑定服务,因为它需要多线程能力而且会导致更加复杂的实现。

继承Binder类
     实现步骤:
     1、在服务中,创建Binder类的实例来完成下列操作之一:
     包含客户端能调用的公共方法;
     返回当前Service实例,其中包含客户端能调用的公共方法;
     返回服务管理的其他类的实例,其中包含客户端能调用的公共方法。
     2、从onBind()回调方法中返回Binder类实例
     3、在客户端,从onServiceConnected()毁掉方法接收Binder实例,并且使用提供的方法调用绑定服务。
     服务和客户端必须位于同一个应用程序的原因是,客户端能转型返回对象并且适当的调用其方法。服务和客户端也必须也位于同一个进程,因为该技术不支持跨进程。
     LocalBinder类为客户端提供了getService()方法来获得当前LocalService的实例。

使用Messenger类
     如果需要服务与远程进行通信,则可以使用Messenger类来为服务提供接口,该技术允许不使用AIDL执行进程间通信IPC。
     使用方法:
     1、实现Handler的服务因为每次从客户端调用而收到回调
     2、Handler用于创建Messenger对象,它是Handler的引用
     3、Messenger创建IBinder,服务从onBind()方法将其返回到客户端
     4、客户端使用IBinder来实例化Messenger,然后使用它来发送Message对象到服务
     5、服务在其Handler的handleMessage()方法接收Message

绑定到服务
     应用程序组件能调用bindService()方法绑定到服务。Android系统接下来调用服务的onBind()方法,它返回IBinder来与服务通信。
     绑定时异步的。bindService()方法理解返回并且不返回IBinder到客户端。为了接收IBinder,客户端必须创建ServiceConnection实例然后将其传递给bindService()方法。ServiceConnection包含系统调用发送IBinder的回调方法。
     只有Activity、Service和ContentProvider能绑定到服务,BroadcastReceiver不能绑定到服务。
     如果需要从客户端绑定服务,需要完成以下操作:
     1、实现ServiceConnection,需要重写onServiceConnected()和onServiceDisconnected()两个回调方法。
     2、调用bindService()方法,传递ServiceConnection实现
     3、当系统调用onServiceConnected()回调方法时,就可以使用接口定义的方法调用服务。
     4、调用unbindService()方法解绑定
     当客户端销毁时,会将其从服务上解绑定。但是当与服务完成交互或者Activity暂停时,最好解绑定以便系统能及时停止不用的服务。


管理Service的生命周期
     服务的生命周期可以分成两个不同的路径
     Started Service
     当其他组件调用startService()方法时,服务被创建。接着服务无限期运行,其自身必须调用stopSelf()方法或者其他组件调用stopService()方法来停止服务。当服务停止时,系统将其销毁。
     Bound Service
     当其他组件调用bindService()方法时,服务被创建。接着客户端通过IBinder接口与服务通信。
客户端通过unbindService()方法关闭连接。多个客户端能绑定到同一个服务并且当他们都解绑定时,系统销毁服务,服务不需要被停止。
     这两条路径并非完全独立,可以绑定已经使用startService()方法启动的服务,此时,stopService()和stopSelf()方法指导全部客户端解绑定时才能停止服务。

















0 0
原创粉丝点击