前言:本篇文章通过对APP启动过程(从点击图标—>Activity可见)的分析,来搞懂这一过程遇到的几个重要的知识点,以解心中的疑惑,同时通过对整个过程的分析,让孤立的知识点串联起来,有个更好的理解和掌握。
一、程序入口——ActivityThread.main()##
Android程序的入口是ActivityThread
类中的main()
方法,就是当我们点击一个APP图标时,系统最开始执行的地方。以后当被人问到这个问题时,就不要回答“Activity的onCreate()方法”了。
public final class ActivityThread {
......
public static void main(String[] args) {
.....
Looper.prepareMainLooper(); //1
ActivityThread thread = new ActivityThread(); //2
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); //3
}
......
}
......
final ApplicationThread mAppThread = new ApplicationThread(); //4
final Looper mLooper = Looper.myLooper();
final H mH = new H()
}
执行的操作###
1、调用prepareMainLooper()
在主线程中创建一个消息队列。
2、创建ActivityThread
对象。
3、创建Handler
对象。
4、创建ApplicationThread
对象
过程讲解###
1、ActivityThread:每个应用程序都对应着一个ActivityThread
实例,其中的main()
方法是程序的入口,通过一系列的初始化操作,它最终的操作是通过调用ActivityThread.handleMessage()
方法接收系统传来的消息,创建Activity。
Q:消息是由谁传递过来的?请看2.
2、ApplicationThread:每个应用程序对应着一个ApplicationThread
对象,它是一个Binder对象,Binder是用来进行IPC(进程间的通信)操作的。所以它的作用是接收AMS传来的远程消息,例如AMS发送star某个Activity,然后ApplicationThread
再通过Handler(线程间的通信)传递给ActivityThread
,ActivityThread
调用handleMessage()
方法来处理这个消息,进行创建Activity的操作。由此可见,ApplicationThread
是ActivityThread
与AMS之间信息传递的桥梁。
Q:AMS又是啥?请看3.
3、AMS(ActivityManagerService):AMS是Android中的一个核心服务,主要负责系统中四大组建(有的文章说不包括BroadcastReceiver)的启动、切换、调度等工作。所以当我们点击打开一个APP时,AMS会向ApplicationThread
发送请求开启一个Activity,然后由ApplicationThread
传递给ActivityThread
来进行具体操作,上面我们已经提到。
现在我们已经知道了消息传递的大体流程,当ActivityThread
收到AMS传来的启动一个Activity的消息后,就会调用handleMessage()
方法创建指定的Activity,具体如何做的呢?
public final class ActivityThread {
......
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
......
handleLaunchActivity(r, null);
......
break;
}
}
}
}
从代码可以看出,它调用了handleLaunchActivity()
方法,那我们进入看看。
public final class ActivityThread {
......
Activity a = performLaunchActivity(r, customIntent);
......
if (a != null) {
......
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
......
}
.......
}
}
该方法又调用了performLaunchActivity()
方法来返回一个Activity,想必Activity应该就是在这个函数中创建完成的了。此方法执行后,又调用了handleResumeActivity()
方法,我们先看performLaunchActivity()
做了什么。
public final class ActivityThread {
......
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Activity activity = null;
......
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
......
return activity;
}
}
二、performLaunchActivity()##
performLaunchActivity()做了哪些事####
1、从ActivityClientRecord
中得到接下来要启动Activity的ComponentName
信息。
2、从ActivityClientRecord
中得到接下来要启动Activity的信息
通过Instrumentation.newActivity
方法,利用LoadedApk的类加载器尝试创建Activity的对象。
3、通过LoadedApk.makeApplication
方法尝试创建Application对象,在这个方法里会通过Class.newInstance()
方法创建Application的对象,并且它的onCreate
方法也是在此时被调用的。
4、为Activity创建ContextImpl的
对象,调用Activity.attach()
方法。
5、调用Activity.setTheme
方法,如果Activity申明时指定了theme的话。
6、调用Activity.onCreate()
方法,然后是onStart()
方法,如果之前有保存的状态那么还会调用onRestoreInstanceState()
方法,最后调用onPostCreate()
方法,至此整个launch过程算是结束了。
进入onCreate()方法####
下面终于进入到onCreate()
方法了,首要执行的就是setContentView(R.layout.main)
,这个方法的目的是设置我们在xml文件中定义的布局,我们进入这个方法看看。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
……
private Window mWindow;
mWindow = new PhoneWindow(this, window);
public Window getWindow() {
return mWindow;
}
该方法中调用了mWindow()
的setContentView()
方法,因为我们可以从代码中看出getWindow()
返回的是mWindow
,mWindow
是Window
类型的,而Window
是一个抽象类,它的实现类是PhoneWindow
。所以, getWindow().setContentView()
方法就是调用的PhoneWindow
的setContentView()
方法,然后我们进入看看。
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
private ViewGroup mContentParent;
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
mContentParent.addView(view, params);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
首先,判断mContentParent
是否为空,为空则执行installDecor()
。mContentParent
是什么?从代码中的注释可以看到说“mContentParent是mDecor本身或者是mDecor的一个子元素
”,mDcor
是DecorView
的实例,大家可能还不明白,所以要先搞清DecorView
是什么,然后我们继续往下看,看看installDecor()
方法做了什么。
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor(); // 1
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor); // 2
...
}
}
}
从代码可以看出,它调用了generateDecor()
方法:
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
好了,可以看出,这里实例化出了一个DecorView
,那DecorView
是什么呢?
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
}
由代码可见,DecorView
继承自FrameLayout
,而FrameLayout
继承自ViewGroup
,所以DecorView
是一个ViewGroup
。其实,它是ViewTree的最顶层的一个View,它是一个FrameLayout
布局,代表了整个应用的界面,由TitlView和ContentView两个子元素,而ContentView则是上面提到的mContentParent
,那为什么刚才注释里说“mContentParent是mDecor本身或者是mDecor的一个子元素
”呢?我们进入installDecor()
中注释的2号代码:
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
// 从主题文件中获取样式信息
TypedArray a = getWindowStyle();
...
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestFeature(FEATURE_ACTION_BAR);
}
if(...){
...
}
// Inflate the window decor.
// 加载窗口布局
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
} else if(...){
...
}
View in = mLayoutInflater.inflate(layoutResource, null); //加载layoutResource
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); //往DecorView中添加子View,即mContentParent
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); // 这里获取的就是mContentParent
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
ProgressBar progress = getCircularProgressBar(false);
if (progress != null) {
progress.setIndeterminate(true);
}
}
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
registerSwipeCallbacks();
}
// Remaining setup -- of background and title -- that only applies
// to top-level windows.
...
return contentParent;
}
由以上代码可以看出:首先根据设置的主题样式来设置DecorView
的风格,比如说有没有titlebar之类的,接着为DecorView
添加子View,而这里的子View则是上面提到的mContentParent
,如果上面设置了FEATURE_NO_ACTIONBAR
,那么DecorView
就只有mContentParent
一个子View,这也解释了上面的疑问:mContentParent是DecorView本身或者是DecorView的一个子元素。
三、handleResumeActivity()##
performLaunchActivity()
执行完了之后,接着会执行handleResumeActivity()
方法,看看源码会执行哪些操作:
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
//...
ActivityClientRecord r = performResumeActivity(token, clearHide); // 这里会调用到onResume()方法
if (r != null) {
final Activity a = r.activity;
//...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow(); // 获得window对象
View decor = r.window.getDecorView(); // 获得DecorView对象
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager(); // 获得windowManager对象
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l); // 调用addView方法
}
//...
}
}
}
该方法内部会先获得与该Activity关联的几个对象:
1、WIndow
对象
2、DecorView
对象
3、WindowManager
对象,它的实现类是WIndowManagerImpl
接着会调用WIndowManagerImpl
的addView()
方法:
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
...
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
}
这里面又调用了mGlobal
的addView()
方法,mGlobal
是WindowManagerGlobal
的一个实例,我们进入该方法:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display); // 1
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView); // 2
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
1、首先实例化一个ViewRootImpl
类。
2、然后调用ViewRootImpl
的setView()
方法,把DecorView
作为参数传进去。在这里,ViewRootImpl
是WMS
与DecorView
之间沟通的一个桥梁。
3、在这个方法内部,会通过跨进程的方式向WMS(WindowManagerService)发起一个调用,从而将DecorView最终添加到Window上。
4、最后通过WMS调用ViewRootImpl.performTraverals
方法开始View的测量、布局、绘制流程。这个下一篇再讲解。
通过前面的讲解,我们可以如此总结:
Android应用程序窗口 = Activity + PhoneWindow + DecorView
DecorView = TitleView + ContentView(layout.xml文件)
画图表示如下(每一层的大小都是一样的,是覆盖关系,这里是为了方便表示出每一层):
Android应用程序窗口模型
参考:
1、http://www.voidcn.com/blog/u012827296/article/p-4991222.html
网友评论