版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】Android中Activity的启动过程有哪些
本篇文章给大家分享的是有关Android中Activity的启动过程有哪些,在下觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着在下一起来看看吧。前言Activity是Android中一个很重要的概念,堪称四大组件之首,关于Activity有很多内容,比如生命周期和启动Flags,这二者想要说清楚,恐怕又要写两篇长文,更何况分析它们的源码呢。不过本文的侧重点不是它们,我要介绍的是一个Activity典型的启动过程,本文会从源码的角度对其进行分析。我们知道,当startActivity被调用的时候,可以启动一个Activity,但是你知道这个Activity是如何被启动的吗?每个Activity也是一个对象,你知道这个对象是啥时候被创建的吗(也就是说它的构造方法是什么时候被调用的)?为什么onCreate是Activity的执行入口?所有的这一切都被系统封装好了,对我们来说是透明的,我们使用的时候仅仅是传递一个intent然后startActivity就可以达到目的了,不过,阅读了本文以后,你将会了解它的背后到底做了哪些事情。在分析之前,我先介绍几个类:Activity:这个大家都熟悉,startActivity方法的真正实现在Activity中Instrumentation:用来辅助Activity完成启动Activity的过程ActivityThread(包含ApplicationThread+ApplicationThreadNative+IApplicationThread):真正启动Activity的实现都在这里源码分析code:Activity#startActivity@Override
public
void
startActivity(Intent
intent)
{
startActivity(intent,
null);
}
@Override
public
void
startActivity(Intent
intent,
Bundle
options)
{
if
(options
!=
null)
{
startActivityForResult(intent,
-1,
options);
}
else
{
//
Note
we
want
to
go
through
this
call
for
compatibility
with
//
applications
that
may
have
overridden
the
method.
startActivityForResult(intent,
-1);
}
}
public
void
startActivityForResult(Intent
intent,
int
requestCode)
{
startActivityForResult(intent,
requestCode,
null);
}说明:显然,从上往下,最终都是由startActivityForResult来实现的接着看code:Activity#startActivityForResultpublic
void
startActivityForResult(Intent
intent,
int
requestCode,
Bundle
options)
{
//一般的Activity其mParent为null,mParent常用在ActivityGroup中,ActivityGroup已废弃
if
(mParent
==
null)
{
//这里会启动新的Activity,核心功能都在mMainThread.getApplicationThread()中完成
Instrumentation.ActivityResult
ar
=
mInstrumentation.execStartActivity(
this,
mMainThread.getApplicationThread(),
mToken,
this,
intent,
requestCode,
options);
if
(ar
!=
null)
{
//发送结果,即onActivityResult会被调用
mMainThread.sendActivityResult(
mToken,
mEmbeddedID,
requestCode,
ar.getResultCode(),
ar.getResultData());
}
if
(requestCode
>=
0)
{
//
If
this
start
is
requesting
a
result,
we
can
avoid
making
//
the
activity
visible
until
the
result
is
received.
Setting
//
this
code
during
onCreate(Bundle
savedInstanceState)
or
onResume()
will
keep
the
//
activity
hidden
during
this
time,
to
avoid
flickering.
//
This
can
only
be
done
when
a
result
is
requested
because
//
that
guarantees
we
will
get
information
back
when
the
//
activity
is
finished,
no
matter
what
happens
to
it.
mStartedActivity
=
true;
}
final
View
decor
=
mWindow
!=
null
?
mWindow.peekDecorView()
:
null;
if
(decor
!=
null)
{
decor.cancelPendingInputEvents();
}
//
TODO
Consider
clearing/flushing
other
event
sources
and
events
for
child
windows.
}
else
{
//在ActivityGroup内部的Activity调用startActivity的时候会走到这里,内部处理逻辑和上面是类似的
if
(options
!=
null)
{
mParent.startActivityFromChild(this,
intent,
requestCode,
options);
}
else
{
//
Note
we
want
to
go
through
this
method
for
compatibility
with
//
existing
applications
that
may
have
overridden
it.
mParent.startActivityFromChild(this,
intent,
requestCode);
}
}
}说明:上述代码关键点都有注释了,可以发现,真正打开activity的实现在Instrumentation的execStartActivity方法中,去看看code:Instrumentation#execStartActivitypublic
ActivityResult
execStartActivity(
Context
who,
IBinder
contextThread,
IBinder
token,
Activity
target,
Intent
intent,
int
requestCode,
Bundle
options)
{
//核心功能在这个whoThread中完成,其内部scheduleLaunchActivity方法用于完成activity的打开
IApplicationThread
whoThread
=
(IApplicationThread)
contextThread;
if
(mActivityMonitors
!=
null)
{
synchronized
(mSync)
{
//先查找一遍看是否存在这个activity
final
int
N
=
mActivityMonitors.size();
for
(int
i=0;
i<N;
i++)
{
final
ActivityMonitor
am
=
mActivityMonitors.get(i);
if
(am.match(who,
null,
intent))
{
//如果找到了就跳出循环
am.mHits++;
//如果目标activity无法打开,直接return
if
(am.isBlocking())
{
return
requestCode
>=
0
?
am.getResult()
:
null;
}
break;
}
}
}
}
try
{
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
//这里才是真正打开activity的地方,核心功能在whoThread中完成。
int
result
=
ActivityManagerNative.getDefault()
.startActivity(whoThread,
who.getBasePackageName(),
intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token,
target
!=
null
?
target.mEmbeddedID
:
null,
requestCode,
0,
null,
null,
options);
//这个方法是专门抛异常的,它会对结果进行检查,如果无法打开activity,
//则抛出诸如ActivityNotFoundException类似的各种异常
checkStartActivityResult(result,
intent);
}
catch
(RemoteException
e)
{
}
return
null;
}说明:我想再说一下这个方法checkStartActivityResult,它也专业抛异常的,看代码,相信大家对下面的异常信息不陌生吧,就是它干的,其中最熟悉的非Unabletofindexplicitactivityclass莫属了,如果你在xml中没有注册目标activity,此异常将会抛出。/*package*/
static
void
checkStartActivityResult(int
res,
Object
intent)
{
if
(res
>=
ActivityManager.START_SUCCESS)
{
return;
}
switch
(res)
{
case
ActivityManager.START_INTENT_NOT_RESOLVED:
case
ActivityManager.START_CLASS_NOT_FOUND:
if
(intent
instanceof
Intent
&&
((Intent)intent).getComponent()
!=
null)
throw
new
ActivityNotFoundException(
"Unable
to
find
explicit
activity
class
"
+
((Intent)intent).getComponent().toShortString()
+
";
have
you
declared
this
activity
in
your
AndroidManifest.xml?");
throw
new
ActivityNotFoundException(
"No
Activity
found
to
handle
"
+
intent);
case
ActivityManager.START_PERMISSION_DENIED:
throw
new
SecurityException("Not
allowed
to
start
activity
"
+
intent);
case
ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw
new
AndroidRuntimeException(
"FORWARD_RESULT_FLAG
used
while
also
requesting
a
result");
case
ActivityManager.START_NOT_ACTIVITY:
throw
new
IllegalArgumentException(
"PendingIntent
is
not
an
activity");
default:
throw
new
AndroidRuntimeException("Unknown
error
code
"
+
res
+
"
when
starting
"
+
intent);
}
}接下来我们要去看看IApplicationThread,因为核心功能由其内部的scheduleLaunchActivity方法来完成,由于IApplicationThread是个接口,所以,我们需要找到它的实现类,我已经帮大家找到了,它就是ActivityThread中的内部类ApplicationThread,看下它的继承关系:privateclassApplicationThreadextendsApplicationThreadNative;publicabstractclassApplicationThreadNativeextendsBinderimplementsIApplicationThread;可以发现,ApplicationThread还是间接实现了IApplicationThread接口,先看下这个类的结构看完ApplicationThread的大致结构,我们应该能够猜测到,Activity的生命周期中的resume、newIntent、pause、stop等事件都是由它触发的,事实上,的确是这样的。这里,我们为了说明问题,仅仅看scheduleLaunchActivity方法code:ApplicationThread#scheduleLaunchActivitypublic
final
void
scheduleLaunchActivity(Intent
intent,
IBinder
token,
int
ident,
ActivityInfo
info,
Configuration
curConfig,
CompatibilityInfo
compatInfo,
int
procState,
Bundle
state,
List<ResultInfo>
pendingResults,
List<Intent>
pendingNewIntents,
boolean
notResumed,
boolean
isForward,
String
profileName,
ParcelFileDescriptor
profileFd,
boolean
autoStopProfiler)
{
updateProcessState(procState,
false);
ActivityClientRecord
r
=
new
ActivityClientRecord();
r.token
=
token;
r.ident
=
ident;
ent
=
intent;
r.activityInfo
=
info;
patInfo
=
compatInfo;
r.state
=
state;
r.pendingResults
=
pendingResults;
r.pendingIntents
=
pendingNewIntents;
r.startsNotResumed
=
notResumed;
r.isForward
=
isForward;
fileFile
=
profileName;
fileFd
=
profileFd;
r.autoStopProfiler
=
autoStopProfiler;
updatePendingConfiguration(curConfig);
queueOrSendMessage(H.LAUNCH_ACTIVITY,
r);
}说明:上述代码很好理解,构造一个activity记录,然后发送一个消息,所以,我们要看看Handler是如何处理这个消息的,现在转到这个Handler,它有个很短的名字叫做Hcode:ActivityThread#H//这个类太长,我只帖出了我们用到的部分
private
class
H
extends
Handler
{
public
void
handleMessage(Message
msg)
{
if
(DEBUG_MESSAGES)
Slog.v(TAG,
">>>
handling:
"
+
codeToString(msg.what));
switch
(msg.what)
{
//这里处理LAUNCH_ACTIVITY消息类型
case
LAUNCH_ACTIVITY:
{
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"activityStart");
ActivityClientRecord
r
=
(ActivityClientRecord)msg.obj;
r.packageInfo
=
getPackageInfoNoCheck(
r.activityInfo.applicationInfo,
patInfo);
//这里处理startActivity消息
handleLaunchActivity(r,
null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
break;
case
RELAUNCH_ACTIVITY:
{
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"activityRestart");
ActivityClientRecord
r
=
(ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
break;
case
PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"activityPause");
handlePauseActivity((IBinder)msg.obj,
false,
msg.arg1
!=
0,
msg.arg2);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
}说明:看来还要看handleLaunchActivitycode:ActivityThread#handleLaunchActivityprivate
void
handleLaunchActivity(ActivityClientRecord
r,
Intent
customIntent)
{
//
If
we
are
getting
ready
to
gc
after
going
to
the
background,
well
//
we
are
back
active
so
skip
it.
unscheduleGcIdler();
if
(fileFd
!=
null)
{
mProfiler.setProfiler(fileFile,
fileFd);
mProfiler.startProfiling();
mProfiler.autoStopProfiler
=
r.autoStopProfiler;
}
//
Make
sure
we
are
running
with
the
most
recent
config.
handleConfigurationChanged(null,
null);
if
(localLOGV)
Slog.v(
TAG,
"Handling
launch
of
"
+
r);
//终于到底了,大家都有点不耐烦了吧,从方法名可以看出,
//performLaunchActivity真正完成了activity的调起,
//同时activity会被实例化,并且onCreate会被调用
Activity
a
=
performLaunchActivity(r,
customIntent);
if
(a
!=
null)
{
r.createdConfig
=
new
Configuration(mConfiguration);
Bundle
oldState
=
r.state;
//看到没,目标activity的onResume会被调用
handleResumeActivity(r.token,
false,
r.isForward,
!r.activity.mFinished
&&
!r.startsNotResumed);
if
(!r.activity.mFinished
&&
r.startsNotResumed)
{
//
The
activity
manager
actually
wants
this
one
to
start
out
//
paused,
because
it
needs
to
be
visible
but
isn't
in
the
//
foreground.
We
accomplish
this
by
going
through
the
//
normal
startup
(because
activities
expect
to
go
through
//
onResume()
the
first
time
they
run,
before
their
window
//
is
displayed),
and
then
pausing
it.
However,
in
this
case
//
we
do
-not-
need
to
do
the
full
pause
cycle
(of
freezing
//
and
such)
because
the
activity
manager
assumes
it
can
just
//
retain
the
current
state
it
has.
try
{
r.activity.mCalled
=
false;
//同时,由于新activity被调起了,原activity的onPause会被调用
mInstrumentation.callActivityOnPause(r.activity);
//
We
need
to
keep
around
the
original
state,
in
case
//
we
need
to
be
created
again.
But
we
only
do
this
//
for
pre-Honeycomb
apps,
which
always
save
their
state
//
when
pausing,
so
we
can
not
have
them
save
their
state
//
when
restarting
from
a
paused
state.
For
HC
and
later,
//
we
want
to
(and
can)
let
the
state
be
saved
as
the
normal
//
part
of
stopping
the
activity.
if
(r.isPreHoneycomb())
{
r.state
=
oldState;
}
if
(!r.activity.mCalled)
{
throw
new
SuperNotCalledException(
"Activity
"
+
ent.getComponent().toShortString()
+
"
did
not
call
through
to
super.onPause()");
}
}
catch
(SuperNotCalledException
e)
{
throw
e;
}
catch
(Exception
e)
{
if
(!mInstrumentation.onException(r.activity,
e))
{
throw
new
RuntimeException(
"Unable
to
pause
activity
"
+
ent.getComponent().toShortString()
+
":
"
+
e.toString(),
e);
}
}
r.paused
=
true;
}
}
else
{
//
If
there
was
an
error,
for
any
reason,
tell
the
activity
//
manager
to
stop
us.
try
{
ActivityManagerNative.getDefault()
.finishActivity(r.token,
Activity.RESULT_CANCELED,
null);
}
catch
(RemoteException
ex)
{
//
Ignore
}
}
}说明:关于原activity和新activity之间的状态同步,如果大家感兴趣可以自己研究下,因为逻辑太复杂,我没法把所有问题都说清楚,否则就太深入细节而淹没了整体逻辑,研究源码要的就是清楚整体逻辑。下面看最后一个方法,这个方法是activity的启动过程的真正实现。code:ActivityThread#performLaunchActivityprivate
Activity
performLaunchActivity(ActivityClientRecord
r,
Intent
customIntent)
{
//
System.out.println("#####
["
+
System.currentTimeMillis()
+
"]
ActivityThread.performLaunchActivity("
+
r
+
")");
ActivityInfo
aInfo
=
r.activityInfo;
if
(r.packageInfo
==
null)
{
r.packageInfo
=
getPackageInfo(aInfo.applicationInfo,
patInfo,
Context.CONTEXT_INCLUDE_CODE);
}
//首先从intent中解析出目标activity的启动参数
ComponentName
component
=
ent.getComponent();
if
(component
==
null)
{
component
=
ent.resolveActivity(
mInitialApplication.getPackageManager());
ent.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();
//用ClassLoader(类加载器)将目标activity的类通过类名加载进来并调用newInstance来实例化一个对象
//其实就是通过Activity的无参构造方法来new一个对象,对象就是在这里new出来的。
activity
=
mInstrumentation.newActivity(
cl,
component.getClassName(),
ent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
ent.setExtrasClassLoader(cl);
if
(r.state
!=
null)
{
r.state.setClassLoader(cl);
}
}
catch
(Exception
e)
{
if
(!mInstrumentation.onException(activity,
e))
{
throw
new
RuntimeException(
"Unable
to
instantiate
activity
"
+
component
+
":
"
+
e.toString(),
e);
}
}
try
{
Application
app
=
r.packageInfo.makeApplication(false,
mInstrumentation);
if
(localLOGV)
Slog.v(TAG,
"Performing
launch
of
"
+
r);
if
(localLOGV)
Slog.v(
TAG,
r
+
":
app="
+
app
+
",
appName="
+
app.getPackageName()
+
",
pkg="
+
r.packageInfo.getPackageName()
+
",
comp="
+
ent.getComponent().toShortString()
+
",
dir="
+
r.packageInfo.getAppDir());
if
(activity
!=
null)
{
Context
appContext
=
createBaseContextForActivity(r,
activity);
CharSequence
title
=
r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration
config
=
new
Configuration(mCompatConfiguration);
if
(DEBUG_CONFIGURATION)
Slog.v(TAG,
"Launching
activity
"
+
r.activityI
+
"
with
config
"
+
config);
activity.attach(appContext,
this,
getInstrumentation(),
r.token,
r.ident,
app,
ent,
r.activityInfo,
title,
r.parent,
r.embeddedID,
r.lastNonConfigurationInstances,
config);
if
(customIntent
!=
null)
{
a
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026六年级道德与法治下册 健康成长之路
- 小数除法单元测试-2024-2025学年人教版数学五年级上册(含答案)
- 向量优化技术就业前景分析
- 如何判断医患关系好坏
- 2024年公司办公写字楼租赁合同5篇
- 2024年保安员工转正申请书
- 2024年“中学学校体育计划”体育工作计划范本(四篇)
- 2023年乡镇开展预防学生溺水专专项行动实施方案
- 2023年教师资格之中学综合素质押题练习试卷A卷附答案
- 2023年江苏省镇江市丹阳市中考化学二模试卷
- 【成都】2025年中国铁路成都局集团有限公司招聘高校毕业生1102人(一)笔试历年典型考题及考点剖析附带答案详解
- 湖南新高考教研联盟暨长郡二十校联盟2026届高三第二次联考英语试题+答案
- 2026新版中国废旧金属回收拆解项目可行性研究报告
- 北京市海淀区2026届高三4月一模英语试卷(含答案)
- 2026年河南省漯河市重点学校小升初英语考试真题试卷(+答案)
- 2026年教科版一年级科学下册全册教案
- 桥梁工程半成品、成品保护措施
- 餐饮服务标准与操作手册
- 生物山西太原市2026年高三年级模拟考试(一)(太原一模)(3.25-3.27)
- 砂石料供应质量控制及保证措施
- 《制药用水检查指南》2026
评论
0/150
提交评论