Android进阶系列之源码分析Activity的启动流程
美女镇楼,辟邪!
源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆。5000多行,要看完得啥时候去了啊。不过做安卓的总有这一天,自从踏上这条不归路,我就认命了。好吧,我慢慢来啃。先从Activity的启动流程开始,一个app启动的底层源码流程。那么我们该去哪里找源码呢,源码其实就在sdk的包里,并不遥远,只是平时我们很少去关注。(从应用层的入口开始,FrameWork层目前我还没那水平,看不明白),如果想从FrameWork层开始的童鞋,这里给个链接,去看看吧。http://www.jianshu.com/p/6037f6fda285,还有老罗讲Activity启动的更详细步骤,可以参考阅读:http://blog.csdn.net/luoshengyang/article/details/6689748
首先找到sdk文件夹目录,打开source文件夹,我选的是android-21目录,在继续打开android文件夹,继续打开app文件夹,找到ActivityThread.java文件,这就是我们平时所说的UI线程(主线程)。
图 1
在打开Android Studio,直接把这个文件用鼠标拖入Studio界面即可。那么开始我们探索源码之路了。
首先,找到整个java文件的入口,不用问大家都知道,main函数,是所有java文件的入口。直接ctrl+F,搜索main,找到入口。开始怼他!
图2
这里不对每句代码进行详细解释,我们只撸对Activity启动有作用的代码。用过Handler的童鞋都知道,Handler是线程之间通讯的工具。第5205行代码,Looper.prepareMianLooper();就是为UI线程绑定Looper和MessageQueue,一个线程中只能有一个Looper和一个MessageQueue,可以有多个Handler这也是为什么我们平时在Activity的住线程中使用Handler传送消息时,只需要创建Handler不需要管Looper和MessageQueue的原因。
我们只需关心主线程做了哪些操作,其他的先不管。第5207行代码创建了ActivityThread的对象,同时调用了一个attach传入一个false。那么找到attach方法。
图3
初始化传入的是false,那么只看if(!system)里的代码,继续寻找和Activity有关的代码,看到5054行代码,创建了一个ActivityManager,这是Activity的管理器,那么我们在看看ActivityManagerNative这个类的getDefault()这个方法,默认返回的ActivityManager里有什么样的配置。找到源码包,搜索ActivityManagerNative,拖入Studio。
图4
这里通过gDefault对象的get()返回IActivityManager,那么看看gDefault又是什么呢。
图5
这里采用IBinder机制,通过ServiceManager获得activity的服务,调用asInterface(IBinder)方法,获得IActivityManager。再看看asInterface()方法。
图6
这里最后返回的是一个ActivityManagerProxy对象,通过代理设计模式来创建实现了IActivityManager接口的类的对象。
再回到图3ActivityThread中,获得了ActivityManager之后,第5056行调用attachApplication(),传入applicationThread类型的Binder对象。那么看一下ActivityManagerProxy的源码。
class ActivityManagerProxy implements IActivityManager
{
...... public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = http://blog.csdn.net/sw5131899/article/details/Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
} ...... }
这里通过Binder驱动程序,最后进入ActivityManagerService的attachApplication函数中。那么我们看看ActivityManagerService中的attachApplication函数。
图7
在这个方法中调用了attachApplicationLocked()方法,这里将操作转发给attachApplicationLocked函数。
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) { http://www.90168.org/
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else if (mStartingProcesses.size() > 0) {
......
} else {
......
} if (app == null) {
......
return false;
} ...... String processName = app.processName;
try {
thread.asBinder().linkToDeath(new AppDeathRecipient(
app, pid, thread), 0);
} catch (RemoteException e) {
......
return false;
} ...... app.thread = thread;
app.curAdj = app.setAdj = -100;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.forcingToForeground = null;
app.foregroundServices = false;
app.debugging = false; ...... boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); ...... boolean badApp = false;
boolean didSomething = false; // See if the top visible activity is waiting to run in this process...
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr != null && normalMode) {
if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (mStackSupervisor.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
......
}
} else {
......
}
} ...... return true;
} ...... }
这里创建了一个ProcessRecord,首先通过pid将它取回来,放在app变量中,然后对app的其它成员进行初始化,最后调用
mStacksupervisor.realStartActivityLocked执行真正的Activity启动操作。这里要启动的Activity通过调用mStacksupervisor.topRunningActivityLocked(null)从堆栈顶端取回来,这时候在堆栈顶端的Activity就是MainActivity了。那么继续来看ActivityStackSupervisor.realStartActivityLocked()的源码.
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException { ....
r.app = app;
....
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
...
try {
if (app.thread == null) {
throw new RemoteException();
}
List<ResultInfo> results = null;
List<Intent> newIntents = null;
...
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState,
results, newIntents, !andResume, mService.isNextTransitionForward(),
profilerInfo); ..... } catch (RemoteException e) {
..
} ... return true;
}
这里最终通过app.thread进入到ApplicationThreadProxy的scheduleLaunchActivity函数中,注意,这里的第二个参数r,是一个ActivityRecord类型的Binder对象,用来作来这个Activity的token值。app.thread.scheduleLaunchActivity调用的是ApplicationThreadProxy的方法,那么再看看ApplicationThreadProxy。
class ApplicationThreadProxy implements IApplicationThread { ...... public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward)
throws RemoteException { www.90168.org
Parcel data = http://blog.csdn.net/sw5131899/article/details/Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
intent.writeToParcel(data, 0);
data.writeStrongBinder(token);
data.writeInt(ident);
info.writeToParcel(data, 0);
data.writeBundle(state);
data.writeTypedList(pendingResults);
data.writeTypedList(pendingNewIntents);
data.writeInt(notResumed ? 1 : 0);
data.writeInt(isForward ? 1 : 0);
mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
} ...... }
函数首先创建一个ActivityClientRecord实例,并且初始化它的成员变量,然后调用ActivityThread类的queueOrSendMessage函数进一步处理。那么再来看看ActivityThread源码的queueOrSendMessage。
public final class ActivityThread { ...... private final class ApplicationThread extends ApplicationThreadNative { ...... // if the thread hasn't started yet, we don't have the handler, so just
// save the messages until we're ready.
private final void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
} ...... private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
} ...... } ......
}
函数把消息内容放在msg中,然后通过mH把消息分发出去,这里的成员变量mH我们在前面已经见过,消息分发出去后,最后会调用H类的handleMessage函数。 这里最后调用ActivityThread类的handleLaunchActivity函数进一步处理。再看看handleLaunchActivity();
public final class ActivityThread { ...... private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...... Activity a = performLaunchActivity(r, customIntent); if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward); ......
} else {
......
}
} ......
}
这里首先调用performLaunchActivity函数来加载这个Activity类,即activity.MainActivity,然后调用它的onCreate函数,最后回到handleLaunchActivity函数时,再调用handleResumeActivity函数来使这个Activity进入Resumed状态,即会调用这个Activity的onResume函数,这是遵循Activity的生命周期的。再看performLaunchActivity的源码。
public final class ActivityThread { ...... private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo,
Context.CONTEXT_INCLUDE_CODE);
} http://www.90168.org/ ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
} if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
} Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
......
} try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation); ...... if (activity != null) {
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mConfiguration);
......
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config); if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstance = null;
r.lastNonConfigurationChildInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
} activity.mCalled = false;
mInstrumentation.callActivityOnCreate(activity, r.state);
......
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
mInstrumentation.callActivityOnPostCreate(activity, r.state);
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) {
...... } catch (Exception e) {
......
} return activity;
} ......
}
从上面可以看到,mInrumentation.callActivityOncreate(),那么在这里进正式进入了Activity的onCreate()方法了。之后会依次调用Activity的生命周期方法。调用生命周期方法的类都是Intrumentation。
到这里就差不多了,应用层从入口到Activity启动调用Activity的生命周期,当然中间也省略了一些不太重要的步骤。最后附一张流程图。
Android进阶系列之源码分析Activity的启动流程的更多相关文章
- JVM源码分析之JVM启动流程
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十四篇. 今天呢!灯塔君跟大家讲: JVM源码分析之JVM启动流程 前言: 执行Java类的main方法,程序就能运 ...
- Tomcat源码分析之—具体启动流程分析
从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息 ...
- [Abp vNext 源码分析] - 1. 框架启动流程分析
一.简要说明 本篇文章主要剖析与讲解 Abp vNext 在 Web API 项目下的启动流程,让大家了解整个 Abp vNext 框架是如何运作的.总的来说 ,Abp vNext 比起 ABP 框架 ...
- Jvm(jdk8)源码分析1-java命令启动流程详解
JDK8加载源码分析 1.概述 现在大多数互联网公司都是使用java技术体系搭建自己的系统,所以对java开发工程师以及java系统架构师的需求非常的多,虽然普遍的要求都是需要熟悉各种java开发框架 ...
- Tomcat源码分析(从启动流程到请求处理)
Tomcat 8.5下载地址 https://tomcat.apache.org/download-80.cgi Tomcat启动流程 Tomcat源码目录 catalina目录 catalina包含 ...
- Android事件分发机制源码分析
Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...
- Solr4.8.0源码分析(5)之查询流程分析总述
Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...
- (转)linux内存源码分析 - 内存回收(整体流程)
http://www.cnblogs.com/tolimit/p/5435068.html------------linux内存源码分析 - 内存回收(整体流程) 概述 当linux系统内存压力就大时 ...
- HDFS源码分析DataXceiver之整体流程
在<HDFS源码分析之DataXceiverServer>一文中,我们了解到在DataNode中,有一个后台工作的线程DataXceiverServer.它被用于接收来自客户端或其他数据节 ...
随机推荐
- python table转空格
有需求: 预留,先上代码: import os def Table_Space(file_name,lis_out,tab_num = 4): file_str = open(file_name,&q ...
- title换行
- nginx访问量统计
1.根据访问IP统计UV awk '{print $1}' access.log|sort | uniq -c |wc -l 2.统计访问URL统计PV awk '{print $7}' acces ...
- 【ASP.NET】VS编译成功后自动生成Nuget包
在VisualStudio项目中,可以在每次编译成功后自动发布nuget包,具体配置过程如下: 1.下载nuget.exe,放置在Visual Studio项目的根目录下. 2.通过命令行生成 ...
- MySQL 日期、时间转换函数
MySQL 日期.时间转换函数:date_format(date,format), time_format(time,format) 能够把一个日期/时间转换成各种各样的字符串格式.它是 str_to ...
- Linux安装mariadb二进制版本
上一篇说了mariadb编译安装过程,但在生产环境中一般使用发布好的二进制版本,由于安装过程和之前一样,不再详细叙述,只是简单概括一下安装过程: 1. 下载 地址为:https://downloads ...
- sh4.case语句
case ... esac 与其他语言中的 switch ... case 语句类似,是一种多分枝选择结构.case 语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令.case语句格式如下: ...
- MongoDB 效率
写入: 插入100万条数据:用InsertMany,耗时16s左右. 读取: 读取300万条数据,耗时3600毫秒.
- 使用NPOI读取Excel报错ICSharpCode.SharpZipLib.Zip.ZipException:Wrong Local header signature
写了一个小程序利用NPOI来读取Excel,弹出这样的报错: ICSharpCode.SharpZipLib.Zip.ZipException:Wrong Local header signature ...
- C++ 字符处理函数
C/C++里有一个头文件#include <ctype.h>,里面定义了很多字符函数,在实际开发中,用起来很方面. int isalpha(int ch) 若ch是字母('A'-'Z', ...