Android基础四大组件——Service

  Service,了解一下?

.什么是service

.service怎么使用?

.为什么要使用service,不使用Thread?

.service的使用需要注意什么?

.servicestartbind区别?

.同一个servicestartService,然后再bindservice,如何把它停止掉?

.onStartCommand不同返回值的区别;

.service生命周期方法OnCreate,onstartCommand,onBind等运行在什么线程?

.ServiceActivity通信方式?

一、service介绍

1.service是服务的意思,和ActivityBroadcase ReceiverContent provider并称android四大组件。service是在一定时间运行在后台不和用户进行交互的组件,处理一些耗时的逻辑或者需要执行长期的任务。每个service都是在manifest.xml文件中<service>进行声明。

 

2.service的种类

在了解service种类之前先了解先学习下IPCALDL

IPCinter-process communication(进程间通信) Binder ,name pipe,message quque

AIDLAndroid interface definition language(内部进程通信的描述语言)

按运行地点分类:

类别

区别

 优点

缺点 

 应用

本地服务(Local

该服务依附在主进程上,

 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。

 主进程被Kill后,服务便会终止。

 非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务。

远程服务(Remote

该服务是独立的进程,

 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。

 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。

 一些提供系统服务的Service,这种Service是常驻的。

其实remote服务还是很少见的,并且一般都是系统服务。

  

按运行类型分类:

类别

区别

应用

前台服务

会在通知一栏显示 ONGOING Notification

当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。

后台服务

默认的服务即为后台服务,即不会在通知一栏显示 ONGOING  Notification

当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。

有同学可能会问,后台服务我们可以自己创建 ONGOING Notification 这样就成为前台服务吗?答案是否定的,前台服务是在做了上述工作之后需要调用 startForeground  android 2.0 及其以后版本 )或 setForeground android 2.0 以前的版本)使服务成为 前台服务。这样做的好处在于,当服务被外部强制终止掉的时候,ONGOING Notification 任然会移除掉。

 

按使用方式分类:

类别

区别

startService 启动的服务

主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService

bindService 启动的服务

该方法启动的服务要进行通信。停止服务使用unbindService

startService 同时也 bindService 启动的服务

停止服务应同时使用stepServiceunbindService

以上面三种方式启动的服务其生命周期也有区别,将在随后给出。

.service的生命周期

service生命周期,从他创建到销毁会有两条路径

service积极活动的生命时间(active lifetime)是从onStartCommand() onBind()被调用开始,它们各自理由startService() bindService()方法传过来的Intent对象。

如果service是被开启的那么它的活动生命周期和整个生命周期一同结束。

如果service是被绑定的它们它的活动生命周期是在onUnbind()方法返回后结束。

注意:尽管一个被开启的service是通过调用 stopSelf()  stopService()来停止的没有一个对应的回调函数与之对应即没有onStop()回调方法。所以,当调用了停止的方法,除非这个service和客户组件绑定,否则系统将会直接销毁它,onDestory()方法会被调用,并且是这个时候唯一会被调用的回调方法。

 

尽管这个图将开启service和绑定service分开,但是任何service包括已经开启的service都是潜在的允许被绑定。如下图已经开启的service再绑定。

 

.service的使用和Thread的区别


很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下。

 

1). ThreadThread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

2). ServiceService android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreateonStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!

  

既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。

  

举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。

  

因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startServiceContext.stopServiceContext.bindServiceContext.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

四、service使用过程中注意点

 

1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity finish 的时候绑定会自动解除,并且Service会自动停止);

2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService 

3、同时使用 startService bindService 要注意到,Service 的终止,需要unbindServicestopService同时调用,才能终止 Service,不管 startService bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService Context 不存在了(如Activity finish 的时候)之后服务才会自动停止;

4、当在旋转手机屏幕的时候,当手机屏幕在”“变换时,此时如果你的 Activity会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。

5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart

6. AndroidManifest.xml Service 元素的常见选项

android:name-------------  服务类名

android:label--------------  服务的名字,如果此项不设置,那么默认显示的服务名则为类名

android:icon--------------  服务的图标

android:permission-------  申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务

android:process----------  表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字

android:enabled----------  如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false

android:exported---------  表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

 

五. service的start和bind区别?

Start启动的serviceservice有独立的生命周期,不依赖组件;

多次调用start方法,会重复调用onStartCommand方法,start启动的service,必须通过stopService或者stopself来停止Service(Intentservice会自动调用stopself)

 

多次调用onBind方法,只会调用一次onBind方法,bind绑定的serviceservice依赖这些这些组件,这些组件全部销毁之后,service也随之销毁

 

.同一个service先startService,然后再bindservice,如何把它停止掉?

 

不论被startService调用几次,只需stopServicestopself)一次;

调用nbindService,必须调用nunbindService方法,同一个组件多次bind一个service,不需要多次调用unbind,只需要一次,这里注意

因此需要调用一次stopServicestopself)和nunbindService方法,执行顺序没有要求,最后一个stopServicestopself)或者unbindService方法会导致serviceonDestory执行,

 

七、onStartCommand不同返回值的区别

 

从源码中可以看到,有四种返回值

 

/**

* 为了兼容版本,并不保证service被杀死之后会再次调用onStartCommand

*/

public static final int START_STICKY_COMPATIBILITY = 0;

 

/**

* service被杀死之后,保存启动状态,但不保存intent,之后系统会尝试重新启动服务,并回调onStartCommand方法

* 如果没有其他启动服务start命令,intent会为null

* 因为在onStartCommand中要注意intent非空判断

*/

public static final int START_STICKY = 1;

 

/**

* 常规操作,除非死之前还有组件调用startService,否则系统不会保存状态并重启service

*/

public static final int START_NOT_STICKY = 2;

 

/**

* service被杀死之后,系统将会组织一次重启service(除非在之前调用stopself方法)

* 被杀死之前最后一次传递的Intent将重新执行

* flag不会传递null intent

*/

public static final int START_REDELIVER_INTENT = 3;

 

 

 

.service生命周期方法OnCreate,onstartCommand,onBind等运行在什么线程?

 

Service是默认运行在主线程的,其生命周期方法也是运行在主线程的,如果需要再service中进行耗时操作,需要另起线程或者使用IntentService,否则会引起ANR

 

 

.ServiceActivity通信方式

 

1. binder + 回调(listener)

主要思路:Acitivity 将实例传入 Service,同时利用回调更新UI

2. binder + Handler

主要思路:Service 持有 ActivityHandler 对象,Service 通过往该Handler send message 的方式,达到通信的目的。

3. 广播 (推荐LocalBroadcastManager

主要思路:利用系统的LocalBroadcastManagerService send messageActivity receive message

4. 开源组件(EventBusotto)

主要思路:利用反射或者注释的方式实现对注册类的注册,然后遍历当前的注册表,通过key进行查询,然后dispatch,调用相应的事件处理方法。(不同的开源框架实现有所区别)

5. AIDL

主要思路://TODO

 

目前Android 组件之间主流的通信方式如上所述的5种,哪种对于项目更加合适,需要考虑的适用情况有:

1进程内通信还是进程间通信

2一对一通信,还是一对多

3单向还是双向

4性能

5其他(安全性,代码可读性,实现复杂性)等等;

 

九. ServiceIntentService

 

我觉得,IntentService 为什么可以处理耗时任务? 应该从源码上面来分析,

IntentService 是直接继承与 Service的,继承Service后 它的代码一共就100多行。
内部在 onCreate()时,新建了一个HandlerThread 实例。
HandlerThread 是一个Thread的 子类,HandlerThread 内部 有点线我们的UI线程,内部一个Looper loop循环一直轮询消息 获得消息 处理消息。)
IntentService, 内部有一个Handler子类 ServiceHandler,它的Looper用的是这个HandlerThread Looper,IntentSerivce onStart()通过发送Message,ServiceHandler在处理Message 调用的是 onHandleIntent。 所以

简单的说一个IntentService,内部就创建了一个线程,通过Android提供的 Handler Message Looper,这些消息处理的类 构成了一个消息处理的模型。所以IntentService onHandleIntent 这个方法其实是在IntentService 中开辟的一个子线程中处理的

 

 

 

 

参考资料:http://www.cnblogs.com/newcj/archive/2011/05/30/2061370.html

          http://www.cnblogs.com/mengdd/archive/2013/03/24/2979944.html

          http://blog.csdn.net/pi9nc/article/details/18764415

猜你喜欢

转载自blog.csdn.net/memory_zhang/article/details/80256222