点击桌面图标. Launcher和要启动的app是两个不同的App, 他们之间的通讯是通过ActivityServiceManager完成的.
整体流程:
(1)点击相应图标之后, Launcher通知AMS要启动哪个app. 而且指定要启动MyApp的哪个界面.
action = “android.intent.action.MAIN”
category = “android.intent.category.LAUNCHER”
cmp = “com.douyu.activity.MainActivity”
所以为什么要在Manifest中指定LAUNCHER和首页, 主要是要把信息注册到Launcher的启动列表中
点击Launcher, 调用Launcher的startActivitySafely, 调用Activity的startActivity---->startActivityForResult, Activity内部会保持一个对Instrumentation的引用, 然后startActivityForResult会调用Instrumentation的execStartActivity
第2个参数: 通过ActivityThread的getApplicationThread方法取到一个Binder对象,它的类型为ApplicationThread,它代表着Launcher所在的App进程。
第3个参数: mToken,这也是个Binder对象,它代表了Launcher,这里也通过Instrumentation传给AMS,AMS一查电话簿,就知道是谁向AMS发起请求了。
这两个参数是伏笔,传递给AMS,以后AMS想反过来通知Launcher,就能通过这两个参数,找到Launcher。
execStartActivity利用工具ActivityManagerNative 获得AMS的代理类AMP, 然后AMN就可以像aidl一样与AMS通讯了
讲这些主要是说, launcher是怎么与AMS通讯的. launcher实际是通过AMS是代理AMP. 通过AIDL一样的通讯过程, 来进行数据交互
(2)然后AMS把要启动的MyApp和首页记录了下来, 通知Launcher休眠
这一部分, AMS处理Launcher传来的启动信息
(2-1)AMN发来启动activity的请求 START_ACTIVITY——TRANSACTION的请求给AMS.同时告诉AMS启动哪个activity.
(2-2)AMS检查MyApp的Manifest文件, 是否存在上面告知的要启动的activity, 没有那么就报错.
(2-3)AMS通知Launcher暂停. 通过第二个参数ApplicationThread这个Binder.
上文execStartActivity第2个参数: 通过ActivityThread的getApplicationThread方法取到一个Binder对象,它的类型为ApplicationThread
(2-4)Launcher通知AMS它休眠了
客户端的ActivityThread是Launcher所在的主线程. 它有一个Binder对象ApplicationThread. 在第一次给AMS通讯的时候, 作为第二个参数传递给AMS. AMS通过这个binder的代理ApplicationThreadProxy与ActivityThread通信, 桥梁是ApplicationThread.
ApplicationThread收到来自AMS的休眠信息, 调用ActivityThread的sendMessage方法, 向Launcher的主线程消息队列发送一个PAUSE_ACTIVITY消息。此时Launcher就休眠了.
(3)然后Launcher进入Paused状态, 然后通知AMS它休眠了
(4)AMS检查MyApp是不是启动了, 是的话, 唤醒MyApp, 否则启动一个新进程.AMS在新进程中创建一个ActivityThread对象, 启动main函数.
启动一个新进程, 就是启动一个新的app
在启动新进程的时候,为这个进程创建ActivityThread对象,这就是我们耳熟能详的主线程(UI线程)。
创建好UI线程后,立刻进入ActivityThread的main函数,接下来要做2件具有重大意义的事情:
1)创建一个主线程Looper,也就是MainLooper。看见没,MainLooper就是在这里创建的。
2)创建Application。记住,Application是在这里生成的。这个Application对象, 以后就是activity的ApplicationContext了
(5)MyApp启动后, 通知AMS已经启动成功.
创建新App的最后,就是告诉AMS,我启动好了,同时把自己的ActivityThread对象发送给AMS,从此以后,AMS的电话簿中就多了这个新的App的登记信息,AMS以后向这个App发送消息,就通过这个ActivityThread对象。
(6)AMS告诉MyApp. 该启动哪个界面
AMS把传入的ActivityThread对象,转为一个ApplicationThread对象,用于以后和这个App跨进程通信。通过代理ApplicationThreadProxy利ApplicationThread这个binder通信。
还记得第1阶段,Launcher发送给AMS要启动斗鱼App的哪个Activity吗?这个信息被AMS存下来了。
那么现在,AMS从过去的记录中翻出来要启动哪个Activity,然后通过ApplicationThreadProxy告诉App。
(7)MyApp启动首页. 并创建Context与首页Activity关联.然后调用Activity的OnCreate函数.
App主线程ActivityThread通过ApplicationThread收到启动哪个activity的消息, 把消息(LAUNCH_ACTIVITY)加到队列中
重新看一下这个过程,每次都是APT执行ActivityThread的sendMessage方法,在这个方法中,把消息拼装一下,然后扔个H的swicth语句去分析,来决定要执行ActivityThread的那个方法。每次都是这样,习惯就好了。
handleLaunchActivity方法都做哪些事呢?
1)通过Instrumentation的newActivity方法,创建出来要启动的Activity实例。
2)为这个Activity创建一个上下文Context对象,并与Activity进行关联。
3)通过Instrumentation的callActivityOnCreate方法,执行Activity的onCreate方法,从而启动Activity。看到这里是不是很熟悉很亲切?
至此,App启动完毕。这个流程是经过了很多次握手, App和ASM,频繁的向对方发送消息,而发送消息的机制,是建立在Binder的基础之上的。
(8)activity的跳转
接下来我们看App内部页面的跳转。
从ActivityA跳转到ActivityB,其实可以把ActivityA看作是Launcher,那么这个跳转过程,和App的启动过程就很像了。
有了前面的分析基础,会发现,这个过程不需要重新启动一个新的进程,所以可以省略App启动过程中的一些步骤,流程简化为:
1)ActivityA向AMS发送一个启动ActivityB的消息。
2)AMS保存ActivityB的信息,然后通知App,你可以休眠了(onPaused)。
3)ActivityA进入休眠,然后通知AMS,我休眠了。
4)AMS发现ActivityB所在的进程就是ActivityA所在的进程,所以不需要重新启动新的进程,所以它就会通知App,启动ActivityB。
5)App启动ActivityB。