1. Activity启动

Activity是一个比较好的模板方法模式。在Android系统启动时,第一个启动的进程是zygote进程,然后由zygote启动SystemServer,再后就是启动AWS、WMS等系统核心服务,这些服务承载着整个Android系统与客户端程序交互。zygote除了启动系统服务与进程之外,普通的用户进程也是由zygote进程fork而来,当一个进程启动起来后,就会加载用户在AndroidManifest.xml中配置的默认加载的Activity,此时加载的入口是ActivityThread.main方法,是整个程序的入口。

main方法主要功能就是创建Application和Activity,并且调用Activity的生命周期函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public static void (String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider()); final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread();
thread.attach(false); if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
} private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
...
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
}
}

上述程序可以看到,在ActivityThread.main中主要的功能就是创建了UI线程消息循环,并启动循环消息循环。最重要的是创建了ActivityThread并调用了attach方法。在方法中又调用了AWS中的attachApplication方法。我们先看看ApplicationThread是什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private class ApplicationThread extends ApplicationThreadNative {
public final void scheduleResumeActivity(IBinder token, int processState,
boolean isForward, Bundle resumeArgs) {
sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
} public final void scheduleLaunchActivity(...) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord(); r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info
r.state = state;
updatePendingConfiguration(curConfig);
...
sendMessage(H.LAUNCH_ACTIVITY, r);
} }

ApplicationThread通过handler管理Activity的生命周期。继续关注AWS中的attachApplication方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
} private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
try {
...
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMod 大专栏  Activity源码解析 - 读书笔记e, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
return false;
}
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
}
}
return true;
}

忽略些代码,这里关注mStackSupervisor.attachApplicationLocked(app)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFrontStack(stack)) {
continue;
}
ActivityRecord hr = stack.topRunningActivityLocked(null);
if (hr != null) {
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (RemoteException e) {
}
}
}
}
}
return didSomething;
}

这里会遍历整个Activity栈并且找出栈顶的ActivityStack,然后调用realStartActivityLocked来真正启动 Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
final ActivityStack stack = r.task.stack;
try {
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
r.icicle, r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
} catch (RemoteException e) {}
return true;
}

ActivityThread的内部类ApplicationThread的scheduleLaunchActivity方法。之后会调ActivityThread的handleLaunchActivity函数,再调用performLaunchActivity来创建Activity,并将Activity和Application关联上。然后调用onCreate方法。

2. setContentView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
} public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
} private void installDecor() {
if (mDecor == null) {
mDecor = return new DecorView(getContext(), -1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
}

setContentView基本流程

  • 构建mDecor对象
  • 设置窗口属性
  • inflate布局

Activity源码解析 - 读书笔记的更多相关文章

  1. STL源码剖析读书笔记之vector

    STL源码剖析读书笔记之vector 1.vector概述 vector是一种序列式容器,我的理解是vector就像数组.但是数组有一个很大的问题就是当我们分配 一个一定大小的数组的时候,起初也许我们 ...

  2. 2015.07.20MapReducer源码解析(笔记)

    MapReducer源码解析(笔记)   第一步,读取数据源,将每一行内容解析成一个个键值对,每个键值对供map函数定义一次,数据源由FileInputFormat:指定的,程序就能从地址读取记录,读 ...

  3. STL源码剖析读书笔记--第四章--序列式容器

    1.什么是序列式容器?什么是关联式容器? 书上给出的解释是,序列式容器中的元素是可序的(可理解为可以按序索引,不管这个索引是像数组一样的随机索引,还是像链表一样的顺序索引),但是元素值在索引顺序的方向 ...

  4. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  5. Stl源码剖析读书笔记之Alloc细节

    阅读基础: Foo *pf = new Foo; 执行了两个步骤: 1)::operator new 向系统申请内存. 2) 调用Foo::Foo()构造函数构造实例.  ==> 申请内存,构造 ...

  6. STL源码剖析读书笔记--第6章&第7章--算法与仿函数

    老实说,这两章内容还蛮多的,但是其实在应用中一点点了解比较好.所以我决定这两张在以后使用过程中零零散散地总结,这个时候就说些基本概念好了.实际上,这两个STL组件都及其重要,我不详述一方面是自己偷懒, ...

  7. STL源码分析读书笔记--第5章--关联式容器

    1.关联式容器的概念 上一篇文章讲序列式容器,序列式容器的概念与关联式容器相对,不提供按序索引.它分为set和map两大类,这两大类各自有各自的衍生体multiset和multimap,的底层机制都是 ...

  8. STL源码分析读书笔记--第三章--迭代器(iterator)概念与traits编程技法

    1.准备知识 typename用法 用法1:等效于模板编程中的class 用法2:用于显式地告诉编译器接下来的名称是类型名,对于这个区分,下面的参考链接中说得好,如果编译器不知道 T::bar 是类型 ...

  9. android源码解析(十七)-->Activity布局加载流程

    版权声明:本文为博主原创文章,未经博主允许不得转载. 好吧,终于要开始讲讲Activity的布局加载流程了,大家都知道在Android体系中Activity扮演了一个界面展示的角色,这也是它与andr ...

随机推荐

  1. 云服务器上安装MSF环境

    在校园网内,禁止使用路由器之类的,所以就导致自己本地虚拟机环境出现各种各样的网络问题,解决起来过于繁琐,为此在服务器上安装MSF 0x00 安装MSF 使用Xshell等工具连上远程服务器后,首先确保 ...

  2. 菜鸟cmake使用

    cmake是用过把源码生成visual studio 工程的工具,也就是生成.sln文件.他会把相应的库依赖都自动添加上. cmake有个CMakeLists.txt (具体语法这里先不介绍) 我都是 ...

  3. 设置PPT版式

    1.点击视图,幻灯片母版 2.选中某个PPT母版,可进行编辑

  4. EMD——EEMD——CEEMD语音增强算法基础

    首先,HHT中用到的EMD详细介绍:https://wenku.baidu.com/view/3bba7029b4daa58da0114a9a.html 本文具体参考 https://zhuanlan ...

  5. [LC] 273. Integer to English Words

    Convert a non-negative integer to its english words representation. Given input is guaranteed to be ...

  6. Linux_打包文件

    将多个文件打包成一个大文件,用tar命令 tar是将多个文件前后连接在一起,tar并不对文件进行压缩 tar -cf  要创建的打包文件名(最后加上.tar)  要打包的文件/列表      c代表创 ...

  7. 39)PHP,选取数据库中的两列

    首先是我的文件关系: 我的b.php是主php文件,BBB.php是配置文件,login.html是显示文件, b.php文件代码: <?php /** * Created by PhpStor ...

  8. Estimating Gene Frequencies| method of maximum likelihood|point estimate

    I.11 Estimating Gene Frequencies 在小样本上计算基因A的概率PA,举例如下: 通过加大样本会将通过观察值得到的数趋近于真实数据,所以该问题转化为了统计学上利用大量观察值 ...

  9. python调用存储过程失败返回1787错误

    (1787, 'When @@GLOBAL.ENFORCE_GTID_CONSISTENCY = 1, the statements CREATE TEMPORARY TABLE and DROP T ...

  10. jQuery实现button按钮提交表单

    在JSP页面中,通常使用button按钮提交表单数据,使用jQuery实现代码如下: <span style="font-family:Comic Sans MS;font-size: ...