目录
[1.2 后台服务](#1.2 后台服务)
[1.4 绑定服务](#1.4 绑定服务)
[3.1 IntentService](#3.1 IntentService)
[3.2 前台Service](#3.2 前台Service)
[3.3 JobService](#3.3 JobService)
**介绍:**Service是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可绑定到服务之间进行交互,甚至是执行进程间通信。
一:Service的分类
从使用场景的角度来说,Service可以分为三种类型,分别是前台服务,后台服务,绑定服务。
1.1:前台服务
前台服务执行一些用户能注意到的操作。例如:音频应用会使用前台服务来播放音频的曲目,必须显示通知。
1.2 后台服务
后台服务不会直接注意到的操作。例如:如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务。
1.4 绑定服务
绑定服务会提供客户端-服务器接口,已便组件与服务进行交互,发送请求,接收结果,甚至是利用进程间通信(IPC)跨进程执行这些操作。
二:Service的创建和启动
创建服务,必须创建Service的子类(或使用它的一个现有子类)。实际开发中,必须重写一些回调方法。
onBind()
当另一个组件想要与服务绑定时,系统会调用bindService()来调用此方法。在此方法的实现中,必须通过返回IBinder提供一个接口,以供客户端来与服务进行通信。请务必实现此方法;但是,如果并不希望允许绑定,则应返回null。
三:使用案例
3.1 IntentService
IntentService是继承与Service并处理异步请求的一个类,在IntentService中有一个工作线程来处理耗时操作,请求的Intent记录会加入队列。
其他组件通过startService来启动IntentService;我们并不需要手动去控制IntenrService,当任务执行完后,IntentService会自动停止;我们启动IntentService多次,每次耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完一个,再到下一个。
3.2 前台Service
当系统内存不足时候,就有可能回收正在后台运行的Service,对于这种情况我们可以使用前台服务,从而让Service稍微没那么容易被系统杀死,当然还是有可能被杀死的,所谓的前台服务就是状态栏显示的Notification。
在自定义的Service类中,重写onCreate(),然后根据自己的需求定制Notification;定制完毕后,调用startForeground(1,notification对象)即可。
3.3 JobService
JobService继承Service,适用于需要特定条件下才执行后台任务的场景。由系统统一管理和调度,在特定场景下使用JobService更加灵活和省心,相当于是Service的加强或者优化。
在特定场景下使用JobService更灵活。
3.3.1 onStartJob()
onStartJob()的回调在UI线程,不可执行耗时逻辑,否则可能造成ANR或者Job被强制销毁(超过8s)。并且,JobService里即便新起了线程,处理的时间也不能超过10min,否则job将被强制销毁。
3.3.2 jobFinished():Job的任务执行完毕后,APP端主动调用,用以通知JobScheduler已经完成任务。该任务执行完后会回调onDestory()。
3.3.3 onStopJob():停止该Job。当JobScheduler检测Job条件不满足的时候,或者job被抢占被取消的时候的强制回调。返回true,即可被强制停止后再度启动起来。
四:Service的跨进程通信
Android应用或者服务运行在不同的进程中是为了安全,稳定,以及内存管理的原因:
安全性:每个进程都单独运行的,可以保证应用层对系统层的隔离。
稳定性:如果某个进程崩溃了不会导致其他进程奔溃。
内存分配:如果某个进程已经不需要了可以从内存中移除,并且回收相应的内存。
那么这并不是说进程间无法进行数据交换,进程间的数据交互,通信,我们常称作跨进程通信,简称IPC。
跨进程通信的方式主要有:
-
使用Intent/Bundle
-
使用文件共享
-
使用Messenger
-
使用AIDL
-
使用ContentProvider
-
使用Socket
其中,使用Message和AIDL方式需要配合Service使用。
Message和AIDL如何选择呢?只有在需要不同应用的客户端通过IPC方式访问服务,并且希望在服务中进行多线程处理时,才有必要使用AIDL;如何想执行IPC,但不需要处理多线程,可以使用Message来实现接口。
4.1 IPC的Message实现
Message,即进程间通信的信使。它是基于Message的进程间通信,我们可以像在线程间利用Handler.send(Message)一样。
Messager底层实现其实就是AIDL跨进程通信使用Messager时,Messager会将所有服务调用加入队列,然后服务端那边一边处理一个调用。
4.2 IPC的AIDL实现
AIDL是安卓接口定义语言。
4.2.1 AIDL支持类型数据类型
-
java基本数据类型:char,byte,short,int,long,float,double,boolean
-
String,CharSequence
-
实现了Parcelable接口的类型
-
List类型和Map类型,要求里面的每个元素都是AIDL支持的类型
4.3 AIDL文件分类
在AIDL中声明实现了Parcelable接口的数据类型
定义接口方法,声明要暴露那些接口给客户端调用
4.4 参数定向TAG
所有的非基本参数都需要一个定向tag来指出数据的流向,不管是in,out,还是inout。参数的定向tag默认是并且只能是in。
in:对于调用方传入的参数对象而言,in表示此对象完整信息会由调用方传入方法实现方,但是如果在方法实现方修改此对象,调用方无法同步修改。
out:表示调用方传入此对象的空对象到方法实现方,但是方法实现方传入的空对象做出任何修改都会同步到调用方:
inout:表示调用方将完整的对象信息传入方法方,方法实现方对此对象修改也会同步到调用方。