想想我们在客户端是如何启动一个Activity的
1.清单文件中声明
2.通过startActivity()启动
这里我主要想分析一下第二种启动方法,暂时不想看解析xml的源码。
直接进入Activity的startActivity()方法,进入Instrumentation的execStartActivity()方法
try {
......
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
......
} catch (RemoteException e) {
}
ActivityManagerNative(写入)是一个Binder,专门用来和运行在服务端的AmS进行IPC通信。
在这里简述一下AmS和Activity有关的功能:
统一调度各应用程序的Activity.所有的应用程序要启动Activity的话,都要先报告给AmS,他会决定该Activity是否可以启动,如果可以,它再发消息给应用程序启动指定的Activity. ——《Android内核剖析》
此时,启动Activity的消息已经发送到了AmS,那么我们在哪里收到AmS发送给应用程序的消息呢?
客官们可以先看看知乎上的一个问题
https://www.zhihu.com/question/34652589/answer/90662131?from=profile_answer_card
我们都知道主线程的概念,也许知道Android程序的入口点是ActivityThread类的main()方法。弄出了一个轮询器,然后不断的从消息队列中拿消息,执行,如果没有消息的话,就处于”休眠” 状态,并不会消耗CPU资源。
关于UI线程
每一行代码都是在线程中执行的,可以这么说,执行ActivityThread的线程就是UI线程。执行完main()方法后,主线程此时就处于轮询状态,接受消息,执行消息中的内容,他就干那些事儿。
可是,我们刚刚说到的接收AmS发来的消息是怎么回事儿
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false); //创建了一个新的线程
......
Looper.loop();
}
和AmS通信是IPC操作,需要不断的从Binder读取数据,这一操作,肯定不是在UI线程做的,那Android就没法弄了啊。
看看main()函数的代码thread.attach(false)
/**将ApplicationThread作为该进程/应用程序的唯一识别(暂时不明白有什么用)
*/
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//这里的实现类是ActivityManagerNative
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
/**
*将发送Binder和接受Binder关联起来,因为系统收到消息后必须
*回发一个消息,系统后面会根据这个标识把数据发送出去
*对应的Binder才能收到数据
*/
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
注:此图来自知乎大神https://www.zhihu.com/people/gityuan
注意图中的箭头,收消息和发消息是分开的,我们在发消息的时候必须带上一个标识,系统收到这个消息后会回发一个消息,那客户端究竟怎么拿到这个消息呢?这个表示就派上用场了,客户端会调用相应的Binder去读取这个消息,这样才不会弄混淆。
下面我们就来看看ActivityThread的方法
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig,...)
{
......
sendMessage(H.LAUNCH_ACTIVITY, r);//发送一个启动Activity的消息
......
}
UI线程Handler的handleMessage()方法
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
......
handleLaunchActivity(r, null);
......
}
}
后面的事情是很容易想到了,利用反射创建一个Activity对象,然后再调用他的各种onCreate(),onResume()方法
try {
......
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
......
}
这就是Activity启动的一个简单分析,最重要的是理解App是怎样和系统进行交互的。