Activity的启动过程第一篇
最近研究动态加载,发现,要想做的好,涉及的面太广了,从classloader 到 android应用程序框架,都要有深刻的了解,所以开 始学习并记录一些知识。希望对大家有所帮助。以下信息基本来自网络或者,老罗的Android系统源代码情景分析。
一般,Aty的启动,包含三个部分,第一个是Laucher , 第二个MainAty(程序的入口Aty),第三个是AMS(AndroidManagerService),他们三个的关系,总结起来一句话就是, Laucher通过AMS 来启动MainAty, 而且 他们三个不在同一个进程中,是靠binder进行通信的
一、先来说Aty的启动过程
1、Laucher组件 首先向AMS(AndroidManagerService)发送一个启动Mainactivity的请求, 这个请求是进程间通信的。
2、AMS首先将要启动的MainActivity组件的信息保留起来,然后向Laucher组件发送一个进入终止状态的进程通信。
3、然后,Laucher组件会接收到AMS发来的中止请求,进入中止状态, 然后再向AMS发送消息,告诉AMS 我已经进入中止状态了,你请继续做你的是事情,这样AMS就能继续进行启动Aty的操作。
4、由于MainAty的启动是在Lauther程序中启动的,Lauther中止了,程序应用进程也就不存在了,然后AMS就会新启动一个应用进程。
5、新的应用进程启动后,就会告诉AMS 我(新的应用进程)已经启动好了,然后发一个通信请求给AMS。
6、接收到新应用进程发来的通信后,AMS就会把第二步保留的组件信息 传递给新的进程,然后新的进程就可以靠这些信息去启动MainAty。
Step1 看源码
//在Launcher里面
void startActivityForResultSafely(Intent intent, int requestCode) {
boolean startActivitySafely(View v, Intent intent, Object tag) {
boolean success = false;
try {
//会调用这个方法
success = startActivity(v, intent, tag);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
}
return success;
}
}
boolean startActivity(View v, Intent intent, Object tag) {
//会把每一个启动的Aty 都放到一个新的任务栈中去启动
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
// Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
if (useLaunchAnimation) {
ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
v.getMeasuredWidth(), v.getMeasuredHeight());
startActivity(intent, opts.toBundle());
} else {
startActivity(intent);
}
return true;
} catch (SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Launcher does not have the permission to launch " + intent +
". Make sure to create a MAIN intent-filter for the corresponding activity " +
"or use the exported attribute for this activity. "
+ "tag="+ tag + " intent=" + intent, e);
}
return false;
}
这个intent里面的信息 就是例如
action = "...intent.action.main"
cataegory = '''.....categroy.laucher'
cmp = "com.suwanroy.Mainactivity"
这些不用说估计大家已经很熟悉了。
OK 那么这个信息是从哪里来的呢 Lauther是从哪里获取这些东西的?
系统在启动的时候,会先启动PMS(PackageManagerService),PMS是用来安装APP的,PMS在安装APP之前,会先解析APP的mainfest文件,得到APP里面的组件信息,然后会启动Launcher,Launcher会在PMS中寻找所有Action为Intent.ActionMain Category为 Intent.CATEGORY_LAUNCHER的组件,然后为他们每一个生成一个APP图标,然后把图标和他们的信息关联起来,用户点击图标就会启动相应的MainAty。
Step2 现在到Activitty
在Launcher 里面调用最终都会调用到Activity类中的startactivityforresult方法。看源码
@Override
public void startActivity(Intent intent, Bundle options) {
//可以看到,resultCode都为-1,所以,这个launcher 不会知道MainAty启动后的东西
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);
}
}
//OK,最终走到了这个方法。
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
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 {
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);
}
}
}
文章不发太长,发太长不利于消化。下一篇,将分析这里面的代码,有书里面的,也有一些自己看源码后的见解,大家喜欢的话可以关注我,以后会主要发一些动态加载,和Android自动化测试的一些东西。大家一起成长,一起进步