转载请注明链接: https://blog.youkuaiyun.com/feather_wch/article/details/50300853
详解Service的原理有帮助,请点个赞!
Service原理详解
版本:2018/9/1-1(18:00)
基础(6)
1、Service是什么?
- 一种
服务型组件
,用于在后台执行一系列计算任务(处理网络事务、播放音乐、文件读写、或者与ContentProvider交互)。- 没有界面的组件。
- Service具有两种状态:
启动状态
和绑定状态
- 本地Service运行在主线程(UI线程)中,因此不能进行耗时操作,需要创建子线程才可以。(BoradcastReceiver也是如此)
2、Service的两种状态
- 启动状态: 进行后台任务,
Service
本身运行在主线程
,因此耗时操作需要在新线程
中处理- 绑定状态: 内部同样可以进行后台运算,但是此时
外界
可以很方便与Service
通信
3、Service如何停止?
- 如果是
启动状态
:stopService()或者Service的stopSelf()来停止。- 如果是
绑定状态
: unBindService()后,Service停止- 如果是
启动&绑定状态
:需要执行unBindeService()和stopService()或者Service的stopSelf(),才能真正停止。
4、Service的分类
- 本地服务:一般的Service
- 远程服务: 通过
android:process
属性,运行在独立进程中。
5、本地服务是什么?
- 该类服务依赖在主进程上而不是独立的进程,一定程度上节约资源。
- 本地服务因为在同一进程内,不需要IPC和AIDL进行交互。
bindService
也方便很多。- 缺点:限制性大,
主进程
被杀死后,服务便会终止
。- 应用场景:需要依附某个进程的服务,比如音乐播放。
6、远程服务是什么?
- 该服务是
独立的进程
,进程名为所在包名 + android:process指定的字符串
。- 定义方式:用
android:process=".service"
- 特点: 主进程被杀死后,该服务依然存在,不受其他进城影响,能为多个进程提供服务,具有灵活性。
- 会消耗更多资源,并且使用AIDL进行IPC比较麻烦,一般用于系统Service。
- 从Android 5.0开始,APP结束后会关闭相关进程树,因此相关的服务也会被杀死。
生命周期(4)
1、Service的生命周期
- 仅仅是
startService
:onCreate()->onStartCommand()->onDestory()- 仅仅是
bindService
:onCreate()->onBind()->onUnbind()->onDestory()- 同时使用
startService
开启服务与bindService
绑定服务:onCreate()->onStartCommand()->onBind()->onUnbind()->onDestory()
2、Service生命周期的
生命周期 | 解释 | 注意点 |
---|---|---|
onCreate() | 第一次启动时调用 | 适合只执行一次的操作 |
onStartCommand() | 执行startService会调用 | 可能会多次调用,bindService不会调用 |
onBind() | 执行bindSevice时调用 | 多次bindService不会导致调用多次 |
onUnbind() | 执行unBindService()时调用 | 返回值会决定,再次bindService()会执行onBind()还是onRebind() |
onDestory() | 销毁 | 做一些清理工作 |
3、onStartCommand()的返回值有什么用?
- 返回
START_STICKY
时,如果Service因为内存不足,被系统杀掉后。如果有了多余内存,会尝试重新创建这个Service。- 并且会调用
onStartCommand()
,其中的Intent将会为null。为了那些循环的音乐播放器,天气预报之类的服务。
// Service.java
public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
4、Service的unbindService生命周期
- 客户端执行
unBindService()
后,回调onUnBind()
方法,如果返回true,Service销毁。- onUnBind()如果返回false,判断是否调用了
stopSelf或者stopService
,调用则继续消息Service- 没有调用,则不会销毁。客户端再次调用
bindService()
, 会执行onRebind()
- 销毁后,调用
bindService()
会执行onBind()
进行绑定。
通信(4)
1、Activity与Service间的通信方式
- Activity调用Service的方法:Activity通过调用bindService,在ServiceConnection的onServiceConnected可以获取到Service的对象实例,然后就可以访问
Service
中的方法.- Service去主动通知Activity的方法:可以通过
回调
来实现—在Activity的ServicConnection的onServiceConnected中去给Service设置实现的接口,该接口会在Service中被调用。- 通过
广播
- 通过
EventBus
2、onBind()和onServiceConnected()实现通信
1-自定义Service,onBind()返回自定义的Binder
class MyService extends Service {
public IBinder onBind(Intent intent) {
return new MyBinder();
}
class MyBinder extends Binder{
MyService getService() {
return MyService.this;
}
}
public void method(){}
}
2-onServiceConnected()去接收Service
class MyServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
// 1、获取Sevice
MyService myService = ((MyService.MyBinder)service).getService();
// 2、调用其方法
myService.method();
}
public void onServiceDisconnected(ComponentName name) {
}
}
3、ServiceConnection的onServiceDisconnected什么时候会被调用?
- 和Service连接意外中断。
- 如因为内存不足,Service被意外释放掉。
4、用户解绑和终止Service会调用onServiceDisconnected吗?
不会
启动模式(21)
1、Service的启动方式有什么区别
startService
:Service与组件的生命周期无关,即使组件退出,Service依然存在。耗电,占内存。bindService
:调用者退出后,Service也会退出。
2、startService
- Service无论调用多少次
startService
,onCreate
只会调用一次,onStartCommand
会调用相应次数。- Service无论调用多少次
startService
,只存在一个Service实例
- 结束Service只需要调用一次
stopService或者stopSelf
- Activity的退出并不会导致Service的退出—除非在onDestory里面调用stopService,但是
退出APP会导致Service的退出!
- 系统资源不足的时候,服务可能会被
Kill
3、bindService
- Service通过
bindService
启动,无论调用多少次,onCreate
只会调用一次,且onStartCommand
不会被调用。- 如果调用
Service
的组件退出,如Activity,Service就会被停止。bindService
开启的Service的通信比较方便,本地服务不需要AIDL和IPC,但是远程服务是需要AIDL和IPC的。
4、startService且同时bindService
onCreate
之调用一次。startService
调用几次,onStartCommand
会调用相同次数。bindService
不会调用onStartCommand
- 调用
unBindService
不会停止Service
,必须调用stopService
和Service自身的stopSelf
来停止。- 如果想停止这种Service,
unBindeService
和stopService
都需要调用,缺一不可。
5、同时开启和绑定有什么作用?
- 能让
Service
一直处于后台运行的状态,即使组件已经退出。- 同时通过
bindService
能方便地与Service
通信- 相比于
广播
的方式,性能更高。
6、Service的注意点
- 手机发生旋转时,Activity的重新创建,会导致之前
bindService
建立的连接断开,Service
会因为COntext的销毁而自动停止。
startService流程
7、Service的启动方法
Intent intent = new Intent(this, MyService.class);
startService(intent);
- Service有
启动状态
和绑定状态
两个状态可以共存
,Service可以既处于启动状态又处于绑定状态
8、Service的startService过程流程图和要点?
graph TD;
1(1.startService);
2(2.mBase.startService);
3(3.startServiceCommon);
4(4.ActivityManager.getService.startService);
5(5.mServices.startServiceLocked);
6(6.bringUpServiceLocked);
7(7.realStartServiceLocked);
8(8.app.thread.scheduleCreateService);
9(9.sendServiceArgsLocked);
10(10.handleMessage);
11(11.handleCreateService);
16(16.app.thread.scheduleServiceArgs);
17(17.handleMessage);
18(18.handleServiceArgs);
19(19.onStartCommand);
1-->2;
2-->3;
3-->4;
4-->5;
5-->6;
6-->7;
7-->8;
7-->9;
8-->10;
10-->11;
9-->16;
16-->17;
17-->18;
18-->19;
- startService(
ContextWrapper.java
):Activity层层继承自ContextWrapper
;内部交由ContextImpl
的startService()
;典型的桥接模式- mBase.startService(
ContextImpl.java
): 交给ContextImpl执行。- startServiceCommon(
ContextImpl.java
): 通过ActivityManagerService
启动服务;IPC- startService(
ActivityManagerService.java
):通过ActiveServices
进行后续工作—调用mServices.startServiceLocked
。- startServiceLocked(
ActiveServices.java
): bringUpServiceLocked- bringUpServiceLocked(
ActiveServices.java
): realStartServiceLocked- realStartServiceLocked(
ActiveServices.java
): 1、app.thread.scheduleCreateService 2、sendServiceArgsLocked- app.thread.scheduleCreateService(
ActivityThread.java
):1. 创建Service 2. 发送消息CREATE_SERVICE
给Handler H- sendServiceArgsLocked(): 用Service的其他方法(如onStartCommand)-IPC通信
- handleMessage(
ActivityThread.java
): 处理消息- handleCreateService(
ActivityThread.java
): 处理第12、13、14、15 四步的工作
, 进行Service的创建工作- 16.app.thread.scheduleServiceArgs: IPC让ActivityThread只去执行其他的生命周期回调。发送消息给Handler H
- 17.handleMessage: 调用
handleServiceArgs
- 18.handleServiceArgs: 执行其他的生命周期,如
onStartCommand
- 19.onStartCommand: Service的回调方法
graph TD;
11(11.handleCreateService);
12(12.cl.loadClass);
13(13.makeApplication);
14(14.service.attach);
15(15.service.onCreate);
11-->12;
11-->13;
11-->14;
11-->15;
- handleCreateService(
ActivityThread.java
): 处理第12、13、14、15 四步的工作
- cl.loadClass().newInstance(): 类加载器创建Service实例。
- packageInfo.makeApplication: 用
LoadedApk
创建Application实例
- service.attach: 创建ContextImpl建立Context和Service的联系。
- service.onCreate(): Service的onCreate(), 并且将Service对象存储到ActivityThread中的一个列表中
9、ActiveServices是什么?
- 辅助ActivityManagerService进行Service管理
- 包括:启动、绑定、停止等
10、ServiceRecord是什么?
- 描述一个Service记录,贯穿整个启动过程
11、ContextWrapper是什么?
- ContextWrapper是Context实现类ContextImpl的包装类
- Activity、Service等都是直接或者间接继承自
ContextWrapper
12、ContextWrapper为什么是典型桥接模式?
见下面的
知识扩展部分
13、桥接模式和代理模式的区别?
见下面的
知识扩展部分
源码解析
14、Service的启动过程源码详细分析
/**
* ======================================
* 1. Activty层层继承自ContextWrapper
* 2. Activty的startService()方法来自于ContextWrapper
* 3. ContextWrapper最终由mBase(ContextImpl)完成-典型桥接
* ======================================
*/
//ContextWrapper.java
public ComponentName startService(Intent service) {
//1. mBase就是Context的实现ContextImpl对象(也就是Activity创建时关联的对象)
return mBase.startService(service);
}
//ContextImpl.java:直接调用startServiceCommon
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
//ContextImpl.java
private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) {
......
//1. 让`ActivityManagerService`启动一个Service服务
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, ...省略...);
......
}
//ActivityManagerService.java
public ComponentName startService(IApplicationThread caller, Intent service, ...) {
/**====================================
* 1. 通过mService(ActiveServices)完成后续过程
* 2. ActiveServices是辅助AMS进行Service管理的类
* -包括:启动、绑定、停止
* 3. `startServiceLocked`方法尾部会调用`startServiceInnerLocked`
*=====================================*/
res = mServices.startServiceLocked(caller, service, ...,userId);
}
//ActiveServices.java
ComponentName startServiceInnerLocked(...,ServiceRecord r) {
......
/**=========================================
* ServiceRecord描述的是一个Service记录(贯穿整个启动过程)
* 1. startServiceInnerLocked并没有完成具体启动工作,而是把后续任务交给了bringUpServiceLocked
* 2. bringUpServiceLocked内部调用`realStartServiceLocked`
* 3. realStartServiceLocked真正启动了Service
*==========================================*/
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
......
return r.name;
}
//ActiveServices.java
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) {
......
/**========================================================
* 创建了Service对象,并且调用了onCreate()方法-IPC通信
* 1. app.thread对象是IApplicationThread类型(Binder)
* 2. 具体实现是ActivityThread(继承了ApplicationThreadNative)
*========================================================*/
app.thread.scheduleCreateService(r, r.serviceInfo, ......);
......
//2. 用于调用Service的其他方法(如onStartCommand)-IPC通信
sendServiceArgsLocked(r, execInFg, true);
......
}
//ActivityThread.java的内部类:ApplicationThread
public final void scheduleCreateService(IBinder token, ...,int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
/**========================================
* 1. 发送消息给Handler H处理
* 2. H会接受消息,并且调用ActivityThread的handleCreateService
*========================================*/
sendMessage(H.CREATE_SERVICE, s);
}
/**====================================
* 完成Service最终启动工作
* //ActivityThread.java
*=====================================*/
private void handleCreateService(CreateServiceData data) {
//1. 通过类加载器创建Service实例
Service service = null;
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
//2. 创建Application对象并调用其onCreate方法(Application是唯一的不会重复创建)
Application app = packageInfo.makeApplication(false, mInstrumentation);
//3. 创建ContextImpl对象并通过Service的attach方法建立两者关系(类似Activity的过程)
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
//4. 调用service的onCreate方法,并且将Service对象存储到ActivityThread中的一个列表中
service.onCreate();
mServices.put(data.token, service);
......
}
/**=============================================================
* ActivityThread中还会通过handleServiceArgs方法调用Service的onStartCommand
*=============================================================*/
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
......
//1. Service的onStartCommand方法
res = s.onStartCommand(data.args, data.flags, data.sta