Android service 总结

这两天研究了下service,把文档好好研读了一下,也看了些例子,先把文档中有用的介绍摘录贴出来,以后有空了再重新整理总结一下。

服务是一个系统组件,它不提供用户界面,可以长期运行在后台执行某些操作。
服务有两种形式: started, bound,当然也可以同时以两种形式运行。主要由你是否实现onStartCommand()允许组件去启动一个服务和是否实现onBind()允许去绑定一个服务。


注:服务是在主线程内运行的,如果有大运算或耗时的操作,需要在服务内新建线程以防止ANR和阻塞UI。


如果一个组件通过startService()启动一个服务(会调用onStartCommand()),这个服务会一直运行至到它自己调用stopSelf()或其它控件调用stopService()停止它。


如果一个组件通过bindService()创建一个服务(onStartCommand不会被调用),它的生命周期和绑定它的组件一样。


在manifest.xml文件里声明service,可以给它添加intent filter属性,如果声明了这个属性,设备中其它应用就可以通过把对应的Intent传入startService来启动它。所以,如果服务只是给本应用使用,不要声明它的这个属性。可以通过设定android:exported为false来保证一个服务是私有的,哪怕你声明了Intent Filters.


通常,创建一个started service,可以通过继承Service或IntentService, IntentService是Service的一个子类,内部创建了一个线程来处理启动服务的请求,如果不需要同时处理多个请求,使用它是一个比较好的选择,只需实现onHandleIntent()方法就行了。


onStartCommand()必须返回一个整型,用来描述当系统杀掉一个服务时,它该怎么处理。有三个值Start_not_sticky(被系统杀掉后,不再重新创建服务,除非有新的Intent要启动服务),Start_Sticky(系统杀掉它后,会重新创建服务并调用onStartCommand(),传一个空intent做为参数), Start_Redeliver_Intent(系统杀掉它后,重新创建服务并调用onStartCommand(),传最后一次被调用时的Intent做参数)。


启动一个服务:可以在一个activity或其它组件中通过调用startService()并传一个对应的Intent作为参数来启动一个服务。startService()方法执行会马上返回并且系统会调用服务的onStartCommand()方法并把Intent传给它。如果此时服务还没有启动,系统会先调用onCreate()启动服务,然后再调用onStartCommand(). 如果服务没有提供绑定,这个传给startService()的Intent就是程序组件和服务进行通信的唯一方式。如果你想让服务可以返回一个结果,可以创建一个用于广播的PendingIntent通过启动服务的Intent传给服务,服务就可以用这个广播来发送结果。(1.研究PendingIntent, 2.不可以传进来一个类似Hanler的回调么?给Handler发消息,让主程序处理)


停止一个服务:服务在执行完onStartCommand()后会继续运行,系统除非资源不足需要释放资源是不会终止一个服务的。服务必须通过它自己调用stopSelf()或其它组件调用stopService()来停止。一旦执行完这个函数,系统会尽快的结束服务。如果服务并发处理多个请求,不能在一个请求处理完后停止服务,因为这时可能刚好接收到第二个请求,停止服务会终止第二个请求。这种情况,可以通过给stopSelf(int startId)传一个参数(onStartCommand()的第三个参数)保证当前请求是要结束的服务最后接收的请求,如果此时正好有新的请求进来,原请求将不是最后一个请求,此时服务不会被停止。
服务运行后,可以通过Toast Notifications 和 Status Bar Notifications 通知用户一些消息。通常推荐Status Bar,用户点击通知后可以激活一个activity。
Foreground 服务是一种用户可以知道它是活动的并且系统不能在需要内存时杀死的服务。前端服务必须为status bar提供一个通知表示服务正在运行,在服务停止或者从前端移走之前,这个通知一直存在的。例如播放器或者收音机在后台运行时,它的服务在状态栏上显示当前的歌曲或节目。调用startForeground()使一个服务在前端运行(研究怎么使用)。




Bound Service: 它是 C/S 接口的服务端,它允许其它组件与它绑定,发送接收接请求甚至进程间通信。通常它只在服务于其它组件时运行,并不会长时期在后台运行。Bound service需要继承Service类并实现onBind()方法。这个方法返回一个IBinder对象,这个对象实现了客户端与服务通信的接口。客户端通过bindService()方法与服务绑定,此时它应该提供一个ServiceConnection类的实现用来监视与服务的连接。bindService()方法被调用时会马上返回并且没有返回值,但系统创建好客户端与服务端的连接后,服务会调用ServiceConnection的onServiceConnected()方法并把可以用来跟服务通信的IBinder传给它。
    多个客户端可以同时与服务连接。但只有第一个客户端绑定时系统会调用onBind()来得到一个IBinder,系统会对其它的请求返回同一个IBinder,并不再调用onBind()。最后一个客户端从服务unbind后,系统会终止服务(除非服务同时也被通过startService()启动)。


创建一个Bound Service:当创建一个Bound Service时,需要提供一个供客户端和服务通信的IBinder,有三种方法定义IBinder接口: 
1.继承Binder类,
   如果服务只被本应用使用且运行在同一个进程(进程是指?跟task关系),应该通过这种方法创建接口并通过onBind()返回一个实例。客户端接收到Binder后可以直接调用它的public方法。如果服务只是在后台为自己的应用工作,这是推荐的方法。唯一不使用这种方法的理由是服务需要为其它应用服务或者要跨进程通信。


2.使用Messenger
如果需要接口跨进程,可以为服务创建一个包含Messenger的接口,服务定义一个Handler来处理各种Message对象。这个Handler是Messenger共享IBinder给客户端,允许客户端给服务发送信息的基础。另外,客户端可以定义一个Messenger使服务可以给它发回调消息。这种方式是进程间通信的最简单的方式,因为Messenger把所有请求放到一个队列中,所以不用考虑线程安全问题。


 
3.使用AIDL Android接口描述语言,将对象分解成操作系统可以理解的基本单元,使它们穿过系统边界,从而达到进程间通信的目的。前面的使用Messenger的方法也是以AIDL主基础的。这种方法可以支持多个请求同时访问,不过服务需要有多线程处理的能力。使用这种方法,需要创建一个.aidl的文件定义接口,使用用Android SDK 工具生成抽象类,使服务继承抽象类就可以处理IPC。


注意:对于大多数应用来说最好不要使用AIDL来创建bound service,因为它需要多线程处理的能力,会使服务的实现变得复杂。只有activity, service, content provider 可以绑定一个服务,不可以在broadcast receiver中绑定服务。




你可能感兴趣的:(多线程,android,service,文档,notifications)