在开始之前,我们先来回忆一下我们对Activity
,Window
,View
的印象;
Activity:Android
四大组件之一,也是我们最常见的页面的宿主,通过setContentView
将xml布局,解析并展示到页面上;
Window:窗口,这是一个抽象类,真正的实现类在PhoneWindow
里,用来管理View
的展示以及事件的分发;
View:Android
的视图,是各种炫酷控件的最终父类,维护了绘制流程以及事件的分发和处理;
下面通过一张图来了解它们的对应关系:
纸上得来终觉浅,绝知此事要躬行!接下来让我们通过源码深入看看底层实现吧;
(1)从上面的一张关系图了解到Activity
和Window
是包含的关系,而Window
的实现是在PhoneWindow
里面,那么Activity
和Window
的关系可以理解为Activity
和PhoneWindow
的关系;到这里就有一个疑问了,为什么Activity
和PhoneWindow
是包含的关系?而不是平等的,或者对称的关系呢?
(2)要想理清它们的关系,目前并没有什么好的头绪,但是我们可以先从Activity
的来源来进行分析,试着从Activity
的来源中能否找到它们的对应关系;说到Activity
的来源,我们就不得不来分析一下Activity
的启动流程,看看Activity
究竟是何方神圣!
(3)Activity
的启动流程涉及到很多系统服务,要完整的分析,会花上很大的篇章,等看完Activity
的启动流程之后,估计我们都忘了看这篇博客的目的的;为了简化流程,这里会从Activity
的创建的方法开始讲起;
Activity的创建是在ActivityThread
的handleLaunchActivity()
方法里面,我们就从这个方法进行分析;
在开始之前,我们先来看几个问题:
源码分析:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) { ... // Initialize before creating the activity // 初始化WindowManagerService WindowManagerGlobal.initialize(); //step1: Activity a = performLaunchActivity(r, customIntent); if (a != null) { ... // step2: handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason); ... } else { ... } } 复制代码
这里面主要分为两步操作,第一步是调用performLaunchActivity
方法,第二步是调用handleResumeActivity
方法,先来看一下performLaunchActivity
方法;
performLaunchActivity
方法解析:private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ... // Step1: ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { // Step2: java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); ... } catch (Exception e) { ... } try { // Step3: Application app = r.packageInfo.makeApplication(false, mInstrumentation); ... if (activity != null) { ... // Step4: activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback); ... activity.mCalled = false; // Step5: if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ... } } r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { ... } return activity; } 复制代码
通过调用createBaseContextForActivity
创建Activity
的上下文Context
,而Context
是一个抽象类,具体的实现是在ContextImpl
里面;
通过调用mInstrumentation
的newActivity
来创建Activity
的实例,里面是通过反射的方式进行创建的;Instrumentation
这个类底层实现是代理模式,用户代理Activity
的各种生命周期的操作;
newActivity
方法里通过工厂模式来创建Activity
的实例;
最终通过ClassLoader
来创建Activity
的实例;
通过调用LoadedApk
的makeApplication
方法来创建全局的上下文Application
调用Activity
的attach
来进行初始化,将之前创建的上下文传进去;
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) { // 将Context赋值给Activity attachBaseContext(context); // 将fragment添加到host mFragments.attachHost(null /*parent*/); // 创建PhoneWindo的实例 mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } ... // 给Window设置管理器,通过系统服务获取的管理器 mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); ... } 复制代码
这里面做的主要操作就是创建了Window
和WindowManager
的实例,Window
的实现是在PhoneWindow
里面,而WindowManager
的实现是在WindowManagerImpl
里面;
@Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); } 复制代码
当Window
创建完了之后,就会触发Activity
的onCreate
方法,通过代理类mInstrumentation
的callActivityOnCreate
方法,最终调用到Activity
的onCreate
方法;
看一下总结流程图:
Activity
中的onCreate
方法的调用:Activity
的onCreate
方法调用了setContentView
来进行布局的加载;
走了父类AppCompatActivity
的setContentView
方法,这里调用了getDelegate
获取实例AppCompatDelegate
,AppCompatDelegate
是一个抽象类,具体实现是在AppCompatDelegateImpl
里面;
AppCompatDelegateImpl
里的setContentView
方法,调用了ensureSubDecor
方法来创建DecorView
,继续跟踪源码往下看;
这里调用了createSubDecor
方法,而这里会走到Window
的setContentView
方法;
到这里似乎有一些眉目了,Activity的setContentView
会通过Window
的setContentView
来设置布局,那么可以理解为Window
管理着Activity
对于View
的一些相关操作;那到底是不是这样呢,继续跟踪分析;
Window
的实现是在PhoneWindow
里面,来看一下PhoneWindow
里的setContentView
的逻辑;
这里调用了installDecor
方法;
最终调用了generateDecor
来创建DecorView
;
看一下流程图:
小结:到这里,
performLaunchActivity
的方法就分析完了,这里的源码看到创建了Window
,并且通过PhoneWindow
的setContentView
来创建DecorView
的操作;这里可以理解为Window
管理着Activity
关于View
的一些操作;
这里并没有发现Activity
和DecorView
的关联,接下来看一下handleResumeActivity
方法,进一步跟踪看看是否有关联;
handleResumeActivity
方法解析:final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { // 通过token获取记录当前Activity的信息类 ActivityClientRecord r = mActivities.get(token); // TODO Push resumeArgs into the activity for consideration // Stpe1: r = performResumeActivity(token, clearHide, reason); if (r != null) { ... // If the window hasn't yet been added to the window manager, // and this guy didn't finish itself or start another activity, // then go ahead and add the window. // 判断是否要添加window // Stpe2: boolean willBeVisible = !a.mStartedActivity; if (!willBeVisible) { try { willBeVisible = ActivityManager.getService().willActivityBeVisible( a.getActivityToken()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (r.window == null && !a.mFinished && willBeVisible) { // 将创建Window和decorView赋值给信息记录类 r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; // 通过manager将decorView添加到页面去; // 具体实现是在 // Stpe3: wm.addView(decor, l); } else { ... } } // If the window has already been added, but during resume // we started another activity, then don't yet make the // window visible. } else if (!willBeVisible) { // 判断window已经被添加了,就不展示这个Window了; if (localLOGV) Slog.v( TAG, "Launch " + r + " mStartedActivity set"); r.hideForNow = true; } ... } 复制代码
调用了performResumeActivity
方法来触发Activity
的onResume
方法;
主要是调用了Activity
的performResume
方法;
@VisibleForTesting public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) { final ActivityClientRecord r = mActivities.get(token); ... try { ... r.activity.performResume(r.startsNotResumed, reason); } catch (Exception e) { ... } return r; } 复制代码
来看一下performResume
方法,
final void performResume(boolean followedByPause, String reason) { // 触发Activity的onStart方法; performRestart(true /* start */, reason); mFragments.execPendingActions(); mLastNonConfigurationInstances = null; mCalled = false; // mResumed is set by the instrumentation // 通过代理类Instrumentation来回调Activity的onReusme方法; mInstrumentation.callActivityOnResume(this); // 回调fragment的onResume方法; mFragments.dispatchResume(); mFragments.execPendingActions(); onPostResume(); if (!mCalled) { throw new SuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onPostResume()"); } } 复制代码
这里面主要分为三步:
第一步:通过performRestart
回调Activity
的onStart
方法;
Instrumentation
来回调Activity
的onReusme
方法;
第三步:回调fragment
的onResume
方法;
通过系统服务来判断当前窗口如果还没有被添加到窗口管理器中,就添加该窗口,将页面设置为可见状态;
将DecorView
添加到WindowManager
里去,ViewManager
是一个抽象类,由前面的分析得知,WindowManager
的实现是在WindowManagerImpl
里面,来看一下WindowManagerImpl
的addView
方法;
最终走的是WindowManagerGlobal
的addView
方法;
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ... ViewRootImpl root; View panelParentView = null; synchronized (mLock) { ... // 创建顶层的View视图管理类 root = new ViewRootImpl(view.getContext(), display); 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 { 将当前的DecorView设置给ViewRootImpl root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } } 复制代码
在这里创建了顶层的View
视图管理类ViewRootImpl
,并将DecorView
设置给ViewRootImpl
;
来看看ViewRootImpl
的setView
方法做了啥?
/** * We have one child */ public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; // 触发View树的布局与绘制 // Schedule the first layout -before- adding to the window // manager, to make sure we do the relayout before receiving // any other events from the system. requestLayout(); } } } 复制代码
这里最终会调用requestLayout
方法触发View
树的绘制;
第一步:调用了scheduleTraversals
方法;
第二步:调用了doTraversal
方法;
第三步:调用了performTraversals
方法;
而performTraversals
最终调用了performMeasure
,performLayout
,performDraw
三个大步骤完成对View
树的绘制;
这个流程在之前的一篇博客里面已经分析过了,感兴趣的可以去看看;
到这里handleResumeActivity
方法差不多就分析完了,在这里我们理清了Activity
和View
之间的关系,是通过Window
的管理器WindowManger
来触发View
的绘制的,也就是说Activity
的View
的绘制流程都是交由Window
的WindowManger
来管理的;
看一下流程图:
让我们来回忆一下开头提到的几个问题;Window
,创建的Window
用来干嘛的?Activity
的attach
方法里面创建了Window
的实现类PhoneWindow
,用于管理View
的创建以及和ViewRootIml
进行一些操作;Activity
和Window
的关系?Window
相当于Activity
的代理类,用于管理View
的创建,以及后续View树绘制的一些操作;Activity
和View
的关系?Activity
不直接操作View
,通过代理类Window
来管理View
的创建以及绘制流程;兄dei,如果我的文章对你有帮助的话,请帮我点个赞吧️,也可以关注一下我的Github和博客;