Android笔记-service启动过程分析:bindService源码分析、startService和bindService区别

本文详细分析了Android中Service的启动流程,尤其是bindService的过程,探讨了bindService与startService的区别。从客户端的bindService方法开始,通过ServiceDispatcher和InnerConnection的交互,解释了ServiceConnection如何实现跨进程通信。接着,文章揭示了在AMS中的bindService流程,指出两者的不同在于AMS的realStartServiceLocked方法中对IntentBindRecord和pendingStarts的处理,以及bindService会触发onServiceConnected回调。最后总结了两者的共同点和不同点。
摘要由CSDN通过智能技术生成

前言:

Service的启动流程将会分为一个系列来讲述。
本系列开始将分析Service的启动过程。
看这个系列文章之前你所需要知道的知识点:
1. 熟悉service的基本用法。
2. 了解bind机制,知道android的客户端和AMS间通信流程。
3. 最好学习过activity的启动流程。

本系列将涉及到以下一些分支:
startService源码分析
bindService源码分析、startService和bindService区别
第二次startService为什么没有调用onCreate
为什么bindService和startService同时调用后需要同时调用unBind和stop才能使服务停止。
前台Service原理

今天这一篇将讲述bindService源码分析:


service启动过程分析

bindService源码分析

bindService、startService区别

分析bindService,不打算像startService一样,分析整个AMS流程。
因为两者的AMS流程很相似,所以打算结合startService流程,分析两者的不同之处。
首先我们要思考一下startService和bindService用法上有什么不同:
1. 服务端:

区别 startService bindService
生命周期 会调用onStartCommend 会调用onBind
返回值 onStartCommend没有返回值 onBind需要返回一个Bind类型的值

2. 客户端

区别 startService bindService
启动 用startService来启动startService 用bindService来启动bindService
参数 startService参数只需要一个Intent bindService参数多需要ServiceConnection
回调 没有回调 需要重写ServiceConnection的onServiceConnected方法

3、其他区别

区别 startService bindService
直接UI更新(非广播或eventbus等其他机制) 不可以 可以
跨进程 不可以 可以

区别大概就是以上几点。可以看出bindService和startService相比,多了一个bind机制,可以让Service和Activity之间相互通信。当然,主要目的是为了可以进行跨进程通信。

ServiceDispatch、InnerConnection

我们先从客户端的bindService方法开始看,
当然,客户端经过一系列调用最终会执行到ContextImpl的bindServiceCommon方法:

 private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;//sd具体实现类是ServiceDispatch
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
        //新建一个ServiceDispatch.InnerConnection,第一个参数是:ServiceConnection
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        //检查正确性
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            //Prepare this {@link Intent} to leave an app process. 跨进程通信准备
            service.prepareToLeaveProcess(this);
            //开始AMS通信,注意参数多了一个sd,该参数包含了ServiceConnection信息
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

bindServiceCommon相比startServiceCommend多了一步sd参数的生成。sd参数是什么?怎么生成的呢?
先来看下获取sd的方法mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);

 public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                sd = map.get(c);
            }
            if (sd == null) {
            //用ServiceConnection生成一个LoadedApk.ServiceDispatcher
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                if (map == null) {
                    map = new ArrayMap<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值