service启动activity_一张图理解Service的绑定过程

本文详细解析了如何将Activity与Service进行绑定,包括AMS在其中的作用和步骤。同时,讨论了后续StartService的过程,并指出在Android 8.0后的一个常见ANR问题及其解决方案,即通过先bindService再startForegroundService来避免启动延迟导致的问题。
摘要由CSDN通过智能技术生成

587abcd891c3bd7e1bacdab64d495653.png

58150f6be8429acc48bc76b148b42736.png
Service的绑定过程

如图,首先我们回答一个问题即

如何将Activity与指定Service绑定?

答:绑定其实就是拿到Service的引用,用于和Service通信,需要通过中介者AMS,所以只要AMS拿到Service句柄就好办了因为AMS通过Activity的bindService方法就很容易拿到句柄了,大概分为三步

1.AMS持有Activity的句柄(引用)

通过bindService就可以知道是哪个activity要绑定服务,

2.AMS先拿到Service的句柄(引用)

首先Activity通过一次进程通信让AMS去启动指定的Service,但AMS自己newInstance Service是不行的,因为都不在一个进程,拿不到.Class文件,但是APP进程是可以的,所以只能又来一次进程通信了,之后APP进程(具体的创建者是ActivityThread)就可以用service的实例去构造binder了,然后通过有一次进程通信将构造的binder返回给AMS,AMS在回调给对应的Activity即可

3.AMS回调Service的句柄给Activity

AMS通过onServiceConnected将Service的句柄回调给Activity

后续的StartService

后续Activity如果再调用StartService,AMS就要检查服务是否启动了,如果启动了就只执行onStartCommand,否则还是需要回调onCreate

应用

通过上述分析,我们其实可以解决android8.0后中一个经常发生的ANR问题

Context.startForegroundService() did not then call Service.startForeground()? 即调用了startForegroundService 五秒后没有调用startForeground?

分析:这5s有可能是AMS通信比较耗时,另外如果你的Service是在子进程的话,进程启动也需要耗时解决方案便是先通过bindService,等待服务启动,启动完成后再调用startForegroundService,可以解决的原因

  • bindService没有startForground的限制
  • startForegroundService和startService一样,会走checkServiceRecord方法,然后执行onStartCommand,所以我们在onStartCommand内部在执行startForeground即可

如下代码所示

private static void reliableStartService(Context context, Intent intent) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // 存在clip进程就没有启动进程的时间了
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O || ProcessUtils.isExistClipProcess()) {
            context.startForegroundService(intent);
            return;
        }
        final ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                context.unbindService(this);
                MMKVUtil.INSTANCE.putLong("start_time_key", System.currentTimeMillis());
                context.startForegroundService(intent);
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
        // 不存在,先用bind启动服务
        context.bindService(intent, connection , Context.BIND_AUTO_CREATE);
    } else {
        context.startService(intent);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值