Android组件学习-Service
什么是Service?
Service是一个后台运行(当然也可以设置成前台运行)的组件, 执行长时间运行且不需要用户交互的任务. 即使应用被销毁也依然可以工作.
这里需要说明的是, Service是后台运行, 但是它仍然运行在主线程. 如果你要在Service内进行网络操作的话, 还是需要另外开一个线程. Service的意义在于, 即使应用销毁了, 异步任务也可以继续进行.
Service的三种形式
Service有启动、绑定、启动且绑定三种形式. 启动形式指调用startService方法启动一个Service, 以这种方式启动的Service会一直执行任务, 即使启动它的组件已经被销毁, 需要人为通过StopService或stopSelf停止; 绑定形式指调用bindService方法将一个服务绑定在组件上, 这种服务会提供一个接口, 允许组件与服务交互, 多个组件可以同时绑定服务, 当所有绑定的组件销毁后, 服务也会被销毁; 启动且绑定指时重写onStartCommand和onBind两个方法, 允许服务与组件交互, 但组件被销毁后服务不会被销毁, 需要人为停止.
Service的创建
使用Service之前, 需要在Manifest文件中声明服务的类名.
创建一个Service的子类时, 一般需要重写下面的几个方法:
onStartCommand方法. 当组件通过startService启动一个Service时, 系统将调用此方法. 一旦调用此方法, 需要调用stopService或stopSelf来人为停止这个Service.
onBind方法. 当组件通过bindService启动一个Service时, 系统将调用此方法. 此方法必须返回一个IBinder, 为组件与Service交互提供接口.
onCreate. 创建服务时, 系统会调用此函数初始化服务. 如果服务已经运行则不会调用此方法.
onDestroy. 当Service不再使用且即将被销毁时, 系统将调用此方法.
示例
示例代码
为了演示Service的三种启动方法, 我写了一个简单的demo. 没有注释, 因为这demo太简单了.
首先是UI布局:
就四个按钮, 很简单吧?
然后是Service的类:
1 | public class MyService extends Service { |
代码逻辑也很简单, 我就是把Service可能会出现的状态用日志输出而已. 这里要说明的是我写的MyBinder的内部类. 上面说了, 在使用绑定服务的时候, 服务需要提供一个接口, 这个接口用来进行服务与控件的交互. 在这里, 继承了Binder的MyBinder类就是一个接口. 它的execute方法大家可以理解为一个实现业务逻辑的方法, 当然大家也可以写很多方法, 并不是说只能写一个方法.
然后是Activity的代码:
1 | public class MainActivity extends AppCompatActivity { |
代码也很好懂, 这里就不再做解释了. 大家要好好看这个代码, 这就是最基本的管理服务的操作.
看完了代码, 我们来看一看实际效果.
启动模式的效果
首先我们看一下启动模式. 依次点击开始服务和结束服务, 看一看日志中会有什么输出:
可以看到这个过程用到了Service的onCreate、onStartCommand和onDestory方法.
然后我们再试一下点击两次开始服务, 接着点击结束服务:
可以看到, onCreat方法只被调用了一次, 这也是意料之中的.
这里再说另外两种不好展示的情况. 首先是只点击结束服务, 日志没有任何输出; 然后是只点击开始服务, 然后杀死进程, 服务会在进程被杀死后自动调用onDestory方法.
绑定模式
然后我们看一下绑定模式. 首先依次点击绑定和解绑:
我们看到, 点击绑定按钮(即调用bindService方法)后, 会依次执行onCreate、onBind、onServiceConnected和execute方法; 点击解绑(即调用unbindService方法)后, 会依次执行unbind和onDestory方法.
然后我们看一下点击两次绑定后再点解绑:
可以看到, 第二次点击绑定并没有什么作用, 这是因为MainActivity已经绑定在了MyService上.
这里再说两种不好展示的情况. 首先是只点击解绑, 程序会直接崩溃; 然后是只点击绑定接着杀死进程, 这种情况下不会调用onDestory和onDestory, **可能存在服务没有杀死的情况, 因此强烈不建议这种情况发生! **
启动绑定模式
这个模式不太好展示, 我就直接说一下结果, 大家可以自己跑一下demo验证.
首先是先点击绑定. 在这种情况下, 再点击开始只会执行onStartCommand方法; 再点击结束会没有任何效果; 再点击解绑会接触绑定并销毁Service.
然后是先点击开始再点击绑定. 在这种情况下, 再点击结束没有任何效果; 再点击解绑只会接触绑定. 在点击结束后解绑会解除绑定并销毁Service; 在解绑后点击结束会销毁Service.
根据上面的实验结果, 我们可以得到Service销毁的条件: **当Service既没有启动也没有绑定时, Service才会被销毁. **
IntentService
最后再提一下IntentService. IntentService主要是用来解决多线程与Service交互的问题. IntentService包含一个队列, 每一次处理时, IntentService只会处理队首的请求.
IntentService默认实现了Service的一系列函数, 它不需要我们人为地来销毁. 在使用它时, 我们只需要重写onHandleIntent方法就可以了.