app的启动都是从application中启动,不过如果接入了tinker,就会有点糊涂。因为manifest中有application,然后有改造后集成自DefaultApplicationLike的ApplicationLike类。ApplicationLike和Application又是什么关系,究竟最开始启动的是哪个类?下面将一一道来。
首先我们先明确tinker更改的只是app所在的进程,没有更改系统的进程,因此启动的application就是manifest中指定的application.也就是RealApplication。代码如下:
RealApplication只是继承TinkerApplication,并调用了父类的构造函数。简单猜测tinker的主要功能在这个类实现,下面就简单分析下这个类。关键代码如下:
TinkerApplication继承自application,在realAppcation中通过调用TinkerApplication的构造函数将delegateClassName和loaderClassName这个两个重要参数传递进来。就是我们项目中改造后的FakeApplication,而loaderClassName这个传的是TinkerLoader这个类。Application的调用都是从attachBaseContext方法开始,这个方法调用父类的attachBaseContext之后,设置了设置UncaughtExceptionHandler,因此使用tinker后出现崩溃的堆栈都是以TinkerUncaughtHandler开头。最后调用onBaseContextAttached方法,这个是我们需要重点关注的方法。
时间相关的用来统计load patch的耗时,可以先忽略。重点来看loadTinker这个方法,看名字是加载tinker。代码如下:
首先通过反射获得loaderClassName所代表的的类对象,loaderClassName就是我们在realapplictaion中传递的com.tencent.tinker.loader.TinkerLoader。之后通过构造函数创建一个TinkerLoader实例后调用tryLoad方法,tryload()的返回结果存放在tinkerResultIntent。这个tryload应该就是加载patch的入口,这里先跳过,后续再介绍。不管加载补丁成功与否都会返回,如果有patch就会在这个阶段加载完成。loadTinker()执行之后会调用ensureDelegate(),代码如下:
ensureDelegate方法的重点在createDelegate()中,createDelegate这个也是通过反射来创建一个delegateClassName的对象,delegateClassName的实际值就是我们在realapplictaion中传递的AA.BB.CC.DD.FakeApplication。因为反射用到的是全限定名,因此在realapplictaion传递的也都是全限定名。执行完ensureDelegate创建对象后接下来调用invokeAppLikeOnBaseContextAttached().这个方法会通过反射的方式调用前面ensureDelegate创建的applicationLike对象的onBaseContextAttached。applicationLike实际上就是我们最开始在realapplictaion传递的FakeApplication,因此这个时候FakeApplication的onBaseContextAttached()方法就会被调用。因为最开始调用的是tryLoad方法会去加载补丁,因此调用onBaseContextAttached的时候就已经patch完了。
系统调用Application的attachBaseContext方法之后,下一个调用Application的onCreate(),下面来看下TinkerApplication的onCreate方法。
主要是调用ensureComponentHotplugInstalled方法和invokeAppLikeOnCreate方法,从日志和逻辑上看ensureComponentHotplugInstalled这个方法只是锦上添花,这里先跳过,后续再介绍。invokeAppLikeOnCreate从名字上看是调用appLike的onCreate方法。
也是通过反射调用applicationLike的onCreate方法,实际上调用的就是FakeApplication的onCreate方法。
至此,application中重要的onBaseContextAttached和onCreate的调用时机就大体清楚了,调用时序图如下:
网友评论