<1>什么是服务?

服务是四大组件之一,用于执行长期运行的任务,并且与用户没有交互

通俗来说就是长期于后台运行的程序(例如后台播放音乐,后台下载文件等)

 

<2>进程的概念

——Android系统中进程分为以下几种:

1,前台进程:显示在最顶部的,直接跟用户进行交互的,例如当前操作的Activity界面

2,可见进程:可以看见,但不能操作,例如在一个Actiivity的顶部弹出一个Dialog,此时Activity不能点击,但能被看见,就是可见进程

3,服务进程:在后台运行的进程

4,后台进程:隐退到后台,不做事的进程

5,空进程:没有任何东西在上面跑,仅作为缓存作用, 目的是下次再启动这个进程的时候会快一点

 

在手机上,如果按HOME键,当前的Activity会退到后台,要么成为后台进程,要么成为服务进程

如果按返回键,才会真正退出程序,成为空进程

因为只有按返回键Activity才是调用了onDestory()方法真正销毁

 

——如果手机此时内存不够用了,会先杀死哪种进程?

首先杀死空进程,然后杀死后台进程,然后杀死服务,但服务被杀死后等待内存够用时,服务又会重新运行

 

——Service中是否可以执行耗时操作?

不可以

虽然服务是在后台运行的,但是Service和Activity都是运行在当前APP所在的main thread(UI主线程)中的,而耗时操作(如网络请求、拷贝数据、大文件)会阻塞主线程,给用户带来不好的体验

如果服务直接执行耗时操作,会出现anr,anr的意思是 android no response(无响应,操作超时)

在Android系统中 前台广播的anr为10s,后台广播为60s

Activity的操作为5s 前台服务为20s,后台服务为200s

如果需要在服务中进行耗时操作,可以选择 IntentService,IntentService是Service的子类,用来处理异步请求

IntentService在onCreate()方法中通过HandlerThread单独开启一个线程来处理Intent请求对象所对应的任务,这样可以避免事务处理阻塞主线程
onHandleIntent()函数针对Intent的不同进行不同的事务处理就可以,执行完一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;

否则ServiceHandler会取得下一个Intent请求传入该函数来处理其所对应的任务

 

<3>服务的生命周期

因为服务一直都是不可见的,而且用户无法进行交互操作,所以它的生命周期阶段比较少

1,onCreat()

2,onStartCommand()(也可以用onStart(),但是onStart()已经过时了)

3,onDestroy()

 

服务的启动和Activity一样,也有显式意图创建和隐式意图创建

 

<4>第一种开启服务的方式——startService

首先新建一个类FirstService继承自Service

Android开发——四大组件之服务Service_生命周期

 

 在Acitivity界面通过显式意图(或隐式意图)的方式来启动服务和关闭服务

Android开发——四大组件之服务Service_生命周期_02

 

 

<5>第二种开启服务的方式——onBind绑定服务

假如我们想使用服务中的一个sayHello()方法,希望在服务运行过程中可以输出一个HELLO

首先,在FirstService类中写这个方法

Android开发——四大组件之服务Service_生命周期_03

 

 然后,在MainActivity中new一个FirstService对象去调用这个方法

Android开发——四大组件之服务Service_生命周期_04

 

 这样可行吗?

答案是不可以,这样会提示如果要new FirstService调用sayHello方法,那么这个方法必须是static

而如果把这个sayHello方法改为static,在FirstService类中又会提示获取不到这个context

为什么呢?因为四大组件其实都是由系统进行创建的,上下文context都是系统给它分配的,如果我们想直接new一个Service是不可以的

 

如果我们想使用服务中的方法,那么就需要用另一种开启服务的方法——onBind

我们可以看到,onBind方法的返回值是一个IBinder对象,所以我们要创建一个对象继承IBinder作为onBind的返回值

Android开发——四大组件之服务Service_启动服务_05

 

 在这个返回的InnerBinder类的对象中我们就可以调用sayHello()方法了

在MainActivity中要做什么呢?

首先是绑定服务

Android开发——四大组件之服务Service_生命周期_06

 

 绑定的时候bindService中第二个参数其实是缺少的,我们要创建一个ServiceConnection对象

第一个是参数是意图对象,第二个参数是回调,第三个参数是标记,这个是自动创建的意思,如果服务没有start,那么会自己创建

Android开发——四大组件之服务Service_绑定服务_07

Android开发——四大组件之服务Service_生命周期_08

 

 然后是解绑服务

Android开发——四大组件之服务Service_后台运行_09

 

最后,我们要使用服务中的sayHello方法,如何使用呢?

直接用绑定服务时创建的那个mRemoteBinder对象调用它里面的callServiceInnerMethod方法就好了

因为这个mRemoteBinder其实就是传过来的InnerBinder

Android开发——四大组件之服务Service_启动服务_10

 

 

<6>两种启动方式的异同

bindService的特点:

如果onBind()方法返回的值为null,那么onServiceConnected方法不会被调用

绑定服务和它所绑的Acitivity是不求同生,但求同死的关系,如果Activity没了,那服务也要解绑

服务在解除绑定后会停止运行

绑定的服务只能解绑一次,多次解绑会抛出异常

绑定的connection要和解锁的connection对应,否则无法解绑

 

1,bindService在系统设置里的APP界面下的running中是没有显示的;而startService是有显示的

2,startService来启动服务,服务是长期在后台运行的,只有stopService才会停止服务

就算你的Activity都没有了,这个service也还是在运行;

Android开发——四大组件之服务Service_后台运行_11

 

 

而bindService来启动服务,随着Activity的结束,它也会结束

所以在不用的时候要unBindService,否则会导致context泄露;

3,starService不可以通讯(不能调用其中的方法);

而bindService可以和服务进行通讯

 

<7>混合启动服务

由于两种启动服务的方式各有优缺点,startService启动的服务可以长期后台运行,但不能跟服务进行通讯;bindService启动的服务不能长期后台运行,但可以和服务进行通讯

所以我们把两种方法结合起来,建立一种既可以长期后台运行,又可以进行通讯的服务

startService的服务的生命周期:onCreate->onStartCommand->onDestroy

bindService的服务的生命周期:onCreate->onBind->onUnbind->onDestroy

结合起来,startService()->bindService()->调用服务中的方法->unbindService()->stopService()

这样就可以让服务长期在后台运行,在解绑服务的时候,并没有执行onDestroy方法,所以服务还是在运行着的

如果startService()->bindService()->stopService()这样是无法进行停止服务的

没有解绑,就没有办法执行stopService()方法

 

所以在实际开发中的流程是:

1,startService开启服务,为了使服务可以长期后台运行

2,bindService拿到服务的控制binder,可以和服务进行通讯

3,调用服务里的方法

4,unBindService解绑服务,否则无法停止服务

(此时解绑了服务,但服务仍然在后台运行)

5,在不需要服务的时候停止服务stopService