Android 四大组件系列详解:
Android 四大组件之—Activity 详解
Android 四大组件系列之—-Service 详解
Android 四大组件系列之—BroadcastReceiver 详解
一. Service简介
Service是Android四大组件之一,Service通常总是称之为“后台服务”,它与Activity很相似,都从Context派生出来,都有属于自己的生命周期,但Service与Activity又有很大的不同,Activity呈现一个供用户操作的界面,是直接与用户交互的组件;而Service是没有用户界面的,是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件,Service可以在后台执行网络请求、播放音乐、O文件操作,或者使用它开发如监控之类的后台程序,如,检测SD卡上文件的变化,实时监控地理信息位置的改变等;
二. Service 的生命周期
1. Service生命周期
(1) onCreate
当Service第一次被创建时回调该方法,onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。
(2) onStartCommand
客户端每次调用startService方法启动Service时回调该方法;
(3) onBind(Intent intent)
Service子类必须实现该方法,该方法返回一个IBinder对象,客户端可以通过该方法与Service进行进程间通信;
(4) onUnbind(Intent intent)
当Service与之前绑定的所有客户端都断开连接时回调该方法;
(5) onDestory
当Service关闭之前回调该方法;
下图是两种启动方式下Service的生命周期:
2. 创建,配置Service
3. 客户端启动 Service 的两种方式
Service 需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,区别如下:
startService()方法启动
调用者与 Service 之间没有关连,即使调用者退出了,服务仍然继续运行
使用Context.startService() 方法启动服务,在服务未被创建时,系统会先调用服务的 onCreate() 方法,接着调用 onStart() 方法。
如果调用 startService() 方法前服务已经被创建,多次调用 startService() 方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
使用 startService() 方法启动的服务,只能调用 Context.stopService() 方法结束服务,服务结束时会调用onDestroy()方法。
只有使用 Context.startService() 方法启动服务时才会回调 onStart() 方法。该方法在服务开始运行时被调用。
bindService()方法启动
调用者与 Service 绑定在了一起,调用者一旦退出,Service 也就跟着终止,通过 bindService(Intent service, ServiceConnection conn, int flags)跟 Service 进行绑定,当绑定成功的时候 Service 会将代理对象通过回调的形式传给 conn,这样就拿到了 Service 提供的服务代理对象, 从而可以调用service 提供的一些接口.
使用 Context.bindService() 方法启动服务,在服务未被创建时,会先调用服务的 onCreate() 方法,接着调用 onBind() 方法。这个时候调用者和服务绑定在一起了; 如果此时调用者退出了,系统就会先调用服务的onUnbind() 方法,接着调用 onDestroy() 方法,导致服务也退出.
如果调用 bindService() 方法前服务已经被绑定,多次调用 bindService() 方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。
如果调用者要与正在绑定的服务解除绑定,可以调用 unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()方法, 接着调用onDestroy()方法。
只有使用Context.bindService()方法启动服务时才会回调onBind()方法, 当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法onBind()被多次调用。
只使用Context.bindService()方法启动服务时才会回调 onUnbind() 方法。该方法在调用者与服务解除绑定时被调用
2. 需要特别注意的点
1. Service运行在主线程中, 不能在service中做耗时操作
需要注意的一点是,由于Service运行在后台,字面上很容易让人误以为Service运行在一个单独的线程里,这时错误的; 其实Service运行在主线程中,Service并不是一个新的线程,更不是一个新的进程,UI主线程是不能执行耗时操作的,否则会出现卡顿,甚至ANR(Application not response),因此,在Service中不能执行太耗时的操作,否则将会阻塞主线程,如果需要执行耗时操作应该在Service中创建一个新的线程.
service也可以运行在单独的进程中, 在清单AndroidManifest.xml 文件配置 service 执行所在的进程 ,让 service 在新的进程中运行:
<service
android:name="com.cxh.serviceTest.service"
android:enabled="true"
android:process=":remote" >
</service>
3. Service 和 Thread 区别
Service 给人的感觉就是一个没有用户界面的线程一样, 如果是这样, 那岂不是和 Thread 作用一样了, 并且service 使用比 Thread 复杂的多, 是不是Android 多此一举了呢?
Service四大组件之一,它运行在独立进程的UI主线程中,不可以执行耗时操作
Thread
是程序执行的最小单元,分配CPU的基本单位,可以开启子线程执行耗时操作;Service
在不同Activity
中可以获取自身实例,可以方便的对Service
进行操作,Thread
几乎在任何地方可以使用, 如果在Activity
中被创建和启动, 当Activity
被销毁,Thread
实例就很难再获取到;
什么时候使用service, 要回答这个问题我们必须要知道 Android 应用进程的优先级:
Android 官方文档进程根据优先级的由高到低分为以下五种:
前台进程: 屏幕正在展示的界面,并且正在与用户交互的,其实任何进程,如果它持有前台activity的服务,那这个进程也有了前台优先级的;
可见进程: 就是能看到的,比如A Activity启动了B Activity,但B Activity是透明或者没有完全覆盖住A Activity,此时A Activity就处于可见进程;
注:给Service 设置 setForground(true) 可以使服务类似于前台进程,可尽量保证服务不会被回收;
服务进程: 当一个进程中有服务(Service)运行时,该进程属于服务进程;
后台进程:按下Home键后Activity在后台运行,该进程就处于后台进程, 当系统内存不足时,这种进程很可能会被回收;
空进程: 就是按back键退出以后的进程,这种进程一般是为了缓存一些数据,当系统内存不足时最先回收空进程。
当系统内存不足的时候,低优先越低的进程越容易被系统回收掉,相反优先级越高的进程,不容易被回收;
如上所述可以知道Service(服务进程)的优先级高于后台的Activity,如果Activity中创建并启动了 Thread,那Service优先级肯定也高于的Thread,因此系统可能在内存不足的时会回收后台的Activity和Thread,但不会轻易回收掉Service;
还有一个问题就是 Activity 中创建的 Thread 如果在 Activity退出时没有将该Thread停止释放掉,那么该Thread将继续在后台运行,会变的不可控,如果系统内存充足它将长时间占用内存。