Android四大组件之Service

Service的工作过程

迷茫,是青春最真实的状态;但奋斗,才是青春的主基调;努力是打败焦虑的绝好方法!

引言

Service的两种工作状态:

  • 启动状态——用于执行后台计算
  • 绑定状态——用于其他组件和Service的交互

注意:这两种状态可以共存,即Service可以处于启动状态并且同时处于绑定状态

  1. 通过Context的startService方法启动Service
   Intent intentService = new Intent(this,MyService.class);
   startService(intentService);
  1. 通过Context的bindService方法绑定Service
   Intent intentService = new Intent(this,MyService.class);
   bindService(intentService,mServiceConnection,BIND_AUTO_CREATE);

启动过程

Service的启动方法调用过程

  1. ContextWrapper.startService
  2. ContextImpl.startService
  3. startServiceCommon
  4. ActivityManagerNative.getDefault().startService
  5. AMS.startService
  6. ActiveServices.startServiceLocked
  7. startServiceInnerLocked
  8. bringUpServiceLocked
  9. realStartServiceLocked
  10. app.thread.scheduleCreateService
  11. ActivityThread.handleCreateService

ContextWrapper.startService -> ContextImpl.startService

从ContextWrapper的实现可以看出,大部分操作都是通过mBase(类型ContextImpl)来实现的。这是一种典型的桥接模式。

ContextImpl.startService -> startServiceCommon

public ComponentName startService(Intent service){
     warnIfCallingFromSystemProcess();
     return startServiceCommon(service,mUser);
}

startServiceCommon -> ActivityManagerNative.getDefault().startService

private ComponentName startServiceCommon(Intent service,UserHandle user){
   try{
       ...
       ComponentName cn = ActivityManagerNative.getDefault().startService(...);
       ...
       return cn;
   }catch(RemoteException e){
      return null;
   }
}

ActivityManagerNative.getDefault().startService -> AMS.startService

Android四大组件之Activity中提过,AMS继承ActivityManagerNative,是它的子类,设计模式中的里氏代换原则说明可以用子类代替父类。
详细见这4到5Android四大组件之Activity
:通过AMS来启动服务的行为是一个远程过程调用。

AMS.startService -> ActiveServices.startServiceLocked

public ComponentName startService(...){
   ...
   synchronized(this){
      ...
      ComponentName res = mServices.startServiceLocked(...);
      ...
      return res;
   }
}

AMS通过mServices这个对象完成后续的Service启动过程,mServices对象类型ActiveServices

ActiveServices.startServiceLocked -> startServiceInnerLocked

ActiveServices是一个辅助AMS进行Service管理的类,包括Service的启动、绑定和停止等。ActiveServices的startServiceLocked 方法的尾部会调用startServiceInnerLocked方法。

startServiceInnerLocked -> bringUpServiceLocked

ComponentName startServiceInnerLocked(ServiceMap smap,Intent service,
        ServiceRecord r,boolean callerFg,boolean addToStarting){
    ...
    String error = bringUpServiceLocked(r,service.getFlags(),callerFg,false);
    ... 
    return r.name;   
} 

ServiceRecord描述的是一个Service记录,ServiceRecord一直贯穿着整个Service的启动过程。startServiceInnerLocked 并没有完成具体的启动工作,而是把后续的工作交给了bringUpServiceLocked方法来处理。

bringUpServiceLocked -> realStartServiceLocked

在bringUpServiceLocked中调用了realStartServiceLocked方法。

realStartServiceLocked -> app.thread.scheduleCreateService
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
app.thread.scheduleCreateService -> ActivityThread.handleCreateService

上述过程已经调用到ApplicationThreadscheduleCreateService方法了。
这个过程和ACtivity的启动是类似的。

  • 发送一个启动Service的消息给Handler处理
    CreateServiceData s = new CreateServiceData (); sendMessage(H.CREATE_SERVICE,s);
  • H会接收这个CREATE_SERVICE消息并通过ActivityThreadhandleCreateService方法来完成Service的最终启动。

在这里插入图片描述
在这里插入图片描述
handleCreateService主要完成了如下几件事:

  • 通过类加载器创建Service的实例。
  • 创建Application对象并调用其onCreate,当然Application的创建过程只会有一次。
  • 创建ContextImpl对象并通过Service的attch方法建立二者之间的关系,这个过程和Activity实际上是类似的,毕竟Service和Activity都是一个Context。
  • 调用Service的onCreate方法并将Service对象存储到ActivityThread中的一个列表中。列表定义如下:
   final ArrayMap<IBinder,Service> mServices = new ArrayMap<IBinder,Service>()
  • Service的onCreate方法被执行了,就意味着Service已经启动了。

绑定过程

Service的绑定方法调用过程

  1. ContextWrapper.bindService
  2. ContextImpl.bindService
  3. ContextImpl.bindServiceCommon
  4. AMS.bindService
  5. bindServiceLocked
  6. bringUpServiceLocked
  7. realStartServiceLocked
  8. ApplicationThread.scheduleBindService
  9. ActivityThread.handleBindService

ContextWrapper.bindService -> ContextImpl.bindService

Service的绑定和Service的启动类似,都要从ContextWrapper开始,ContextWrapper的实现是ContextImpl。

ContextImpl.bindService -> ContextImpl.bindServiceCommon

bindService 最终调用自己的bindServiceCommon方法。

ContextImpl.bindServiceCommon -> AMS.bindService
在这里插入图片描述在这里插入图片描述

看图可见,bindServiceCommon调用了ActivityManagerNative.getDefault().bindService。前面已经说过,AMS extends ActivityManagerNative,所以就是调用了AMS的bindService方法。


bindServiceCommon方法完成的事情

  • 将客户端的ServiceConnection对象转换为ServiceDispatcher.InnerConnection对象。由LoadedApk的getServiceDispatcher方法完成。

不能直接使用ServiceConnection对象,是因为服务的绑定可能是跨进程的,所以需要借助Binder才可以让远程服务端回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当了Binder这个角色
ServiceDispatcher的作用:连接ServiceConnection和InnerConnection。
总之,就是将ServiceConnection转换为InnerConnection,使其可以跨进程;然后通过ServiceDispatcher将它们连接起来。

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
         Context context,Handler handler,int flags){
    synchronized(mServices){
        //连接ServiceConnection和InnerConnection的工具类
        LoadedApk.ServiceDispatcher sd = null;
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = 
        mServices.get(context);
        if(map != null){
           //查找是否存在相同的ServiceConnection
           sd = map.get(c);
        }
        //不存在
        if(sd == null){
           //新建一个工具类
           sd = new ServiceDispatcher(c,context,handler,flags);
           if(map == null){
              //新建一个关系
              map = new ArrayMap<ServiceConnection,LoadedApk
              .ServiceDispatcher>();
              //存储到mServices中
              mServices.put(context,map);
           }
           //在关系表中加入这个ServiceConnection和ServiceDispatcher的映射关系
           map.put(c,sd);
        }else{
           //存在
           sd.validate(context,handler);
        }
        //返回其保存的ServiceDispatcher
        //里面保存了ServiceConnection对象和InnerConnection对象
        return sd.getIServiceConnection();
    }    
}

当Service和客户端建立连接后,系统会通过InnerConnection来调用ServiceConnection中的onServiceConnected方法,这个过程可能是跨进程的。
当ServiceDispatcher创建好了以后,getServiceDispatcher会返回其保存的InnerConnection对象。

  • 通过AMS来完成具体绑定过程

AMS.bindService -> bindServiceLocked

public int bindService(...){
   ...
   synchronized(this){
       return mServices.bindServiceLocked(...);
   }
}

bindServiceLocked -> bringUpServiceLocked

bindServiceLocked中调用bringUpServiceLocked方法

bringUpServiceLocked -> realStartServiceLocked

bringUpServiceLocked中调用realStartServiceLocked方法

realStartServiceLocked -> ApplicationThread.scheduleBindService

realStartServiceLocked的执行逻辑和Service启动中的类似,都是通过ApplicationThread来完成Service的实例的创建并执行onCreate方法。
不同的是Service的绑定中的ApplicationThread的scheduleBindService方法在ActiveServices的requestServiceBindingLocked中;而启动的ApplicationThread的scheduleCreateService方法就在realStartServiceLocked中。

ApplicationThread.scheduleBindService -> ActivityThread.handleBindService

这个阶段已经说了很多了,scheduleBindService方法中发送一个绑定Service的信号给Handler,Handler处理消息,然后调用handleBindService方法,进行Service的提取和绑定


handleBindService源码
在这里插入图片描述

handleBindService所做的事

  • 根据Service的token取出Service对象。
  • 调用Service的onBind方法,返回一个Binder供客户端使用。
  • onBind方法调用以后,Service就算绑定了。
  • 通知客户端Service已连接,所以必须调用ServiceConnection中的onServiceConnected,这个过程由AMS的publishService方法来完成。

当多次绑定同一个Service时,onBind只会调用一次,除非Servie被终止了。

告知客户端Service已连接的方法调用过程:

  • AMS.publishService
  • ActiveServices.publishServiceLocked
  • InnerConnection.connected
  • ServiceDispatcher.connected
  • H.post(new RunConnection(name,service,0))
  • ServiceDispatcher.doConnected
    由于ServiceDispatcher内部保存了客户端的ServiceConnection对象,所以可以很方便的调用ServiceConnection的onServiceConnected方法。然后客户端收到消息,了解服务已连接。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值