源码分析

接着上一篇 Activity启动流程源码分析-setContentView源码阅读 的讲解,本节介绍一下Activity的生命周期函数何时被调用

要看Activity的生命周期函数何时被调用,不得不翻阅 ActivityThread 这个类

在这个类里面我们先找到 handleLaunchActivity 这个方法

/*** Extended implementation of activity launch. Used when server requests a launch or relaunch.*/@Overridepublic Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();mSomeActivitiesChanged = true;if (r.profilerInfo != null) {mProfiler.setProfiler(r.profilerInfo);mProfiler.startProfiling();}// Make sure we are running with the most recent config.handleConfigurationChanged(null, null);if (localLOGV) Slog.v(TAG, "Handling launch of " + r);// Initialize before creating the activityif (!ThreadedRenderer.sRendererDisabled) {GraphicsEnvironment.earlyInitEGL();}WindowManagerGlobal.initialize();//这个就是调用 onCreate 的方法final Activity a = performLaunchActivity(r, customIntent);if (a != null) {r.createdConfig = new Configuration(mConfiguration);reportSizeConfigurations(r);if (!r.activity.mFinished && pendingActions != null) {pendingActions.setOldState(r.state);pendingActions.setRestoreInstanceState(true);pendingActions.setCallOnPostCreate(true);}} else {// If there was an error, for any reason, tell the activity manager to stop us.try {ActivityManager.getService().finishActivity(r.token, Activity.RESULT_CANCELED, null,Activity.DONT_FINISH_TASK_WITH_ACTIVITY);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}}return a;}

在这个代码块中,我们主要关心一下这个方法 performLaunchActivity() 我们点进去看一下这个方法的具体实现

/**  Core implementation of activity launch. */private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {//前面省略了 亿行 代码activity.mCalled = false;if (r.isPersistable()) { // callActivityOnCreate 这个是回调 OnCreate 的主要方法mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onCreate()");}r.activity = activity;}r.setState(ON_CREATE);mActivities.put(r.token, r);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;}

在这个代码块中,我们主要关心一下这个方法 callActivityOnCreate () 我们点进去看一下这个方法的具体实现

/*** Perform calling of an activity's {@link Activity#onCreate}* method.  The default implementation simply calls through to that method.*  @param activity The activity being created.* @param icicle The previously frozen state (or null) to pass through to* @param persistentState The previously persisted state (or null)*/public void callActivityOnCreate(Activity activity, Bundle icicle,PersistableBundle persistentState) {prePerformCreate(activity);// performCreate 是我们主要关心的方法,他在 Activity 类里面activity.performCreate(icicle, persistentState);postPerformCreate(activity);}

在这个代码块中,我们主要关心一下这个方法 performCreate() 我们点进去看一下这个方法的具体实现

final void performCreate(Bundle icicle) {performCreate(icicle, null);}final void performCreate(Bundle icicle, PersistableBundle persistentState) {mCanEnterPictureInPicture = true;restoreHasCurrentPermissionRequest(icicle);if (persistentState != null) {//在这里我们调用了 onCreate 方法onCreate(icicle, persistentState);} else {onCreate(icicle);}writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate");mActivityTransitionState.readState(icicle);mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(com.android.internal.R.styleable.Window_windowNoDisplay, false);mFragments.dispatchActivityCreated();mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());}

分析了这么多,大家可能会有点懵,这是初看源码者的通病,想有效解决这个问题,大家就得始终牢记这最初的目的来看

我们的目的是想知道 OnCreate () 何时被调用,说简单点其实就是在 performLaunchActivity() 方法中被调用,而下面被延伸出来的哪些方法只不过是 performLaunchActivity()方法的具体实现,被放到了各个地方而已

然后,我们会调用 handleResumeActivity

@Overridepublic void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {//前面省略亿行代码if (r.window == null && !a.mFinished && willBeVisible) {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 (r.mPreserveWindow) {a.mWindowAdded = true;r.mPreserveWindow = false;// Normally the ViewRoot sets up callbacks with the Activity// in addView->ViewRootImpl#setView. If we are instead reusing// the decor view we have to notify the view root that the// callbacks may have changed.ViewRootImpl impl = decor.getViewRootImpl();if (impl != null) {impl.notifyChildRebuilt();}}if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded = true;//关键所在wm.addView(decor, l);} else {// The activity will get a callback for this {@link LayoutParams} change// earlier. However, at that time the decor will not be set (this is set// in this method), so no action will be taken. This call ensures the// callback occurs with the decor set.a.onWindowAttributesChanged(l);}}// 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) {if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");r.hideForNow = true;}// Get rid of anything left hanging around.cleanUpPendingRemoveWindows(r, false /* force */);// The window is now visible if it has been added, we are not// simply finishing, and we are not starting another activity.if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {if (r.newConfig != null) {performConfigurationChangedForActivity(r, r.newConfig);if (DEBUG_CONFIGURATION) {Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig "+ r.activity.mCurrentConfig);}r.newConfig = null;}if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);WindowManager.LayoutParams l = r.window.getAttributes();if ((l.softInputMode& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)!= forwardBit) {l.softInputMode = (l.softInputMode& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))| forwardBit;if (r.activity.mVisibleFromClient) {ViewManager wm = a.getWindowManager();View decor = r.window.getDecorView();wm.updateViewLayout(decor, l);}}r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {r.activity.makeVisible();}}r.nextIdle = mNewActivities;mNewActivities = r;if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);Looper.myQueue().addIdleHandler(new Idler());}

在这个代码块里我们需要关注的是 addView()这个方法,我们的主要目的是它调用了那个类里面的 addView()

初次看是 vm 的,于是我们得知道 vm 到底是一个什么东西

ViewManager wm = a.getWindowManager();  //a 代表 activity 实例,所以我们得去 activity 里找getWindowManager() 方法,看他到底返回的是什么
 /** Retrieve the window manager for showing custom windows. */public WindowManager getWindowManager() {return mWindowManager;}

从上面可以看出给我们返回的是 mWindowManager ,很明显,这不是最终结果

我们还得深究 给我们返回的 mWindowManager  是个什么东西

mWindowManager = mWindow.getWindowManager();

从上面可以看到,他又调用了 Window 类里面的 getWindowManager()

mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

从上面这行代码 可以看出 mWindowManager  是由 createLocalWindowManager() 创建的

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {return new WindowManagerImpl(mContext, parentWindow);}

即他返回了一个 WindowManagerImpl 对象

从而 可以调用 WindowManagerImpl实例里的 addView 方法,即

@Overridepublic void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {applyDefaultToken(params);mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);}

下面我们再来看 mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); 这个方法干了啥

public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {// do this last because it fires off messages to start doing thingstry {//这个是关键root.setView(view, wparams, panelParentView);} catch (RuntimeException e) {// BadTokenException or InvalidDisplayException, clean up.if (index >= 0) {removeViewLocked(index, true);}throw e;}}}

其中有一个关键语句 root.setView(view, wparams, panelParentView);  root是 ViewRootImpl 的一个实例 他调用了 setView() 方法

/*** We have one child*/public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {// 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()方法的具体实现如下

@Overridepublic void requestLayout() {if (!mHandlingLayoutInLayoutRequest) {checkThread();  //这里就是为什么只能在主线程更改 UI 了mLayoutRequested = true;scheduleTraversals();  //绘制布局的关键方法}}

scheduleTraversals() 方法的具体实现

void scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled = true;mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();mChoreographer.postCallback( //mTraversalRunnable是我们需要关心的,点进去看看Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);if (!mUnbufferedInputDispatch) {scheduleConsumeBatchedInput();}notifyRendererOfFramePending();pokeDrawLockIfNeeded();}}

mTraversalRunnable

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

我们再来看看 TraversalRunnable 类

final class TraversalRunnable implements Runnable {@Overridepublic void run() {doTraversal(); //关键方法}}

doTraversal()具体实现

void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled = false;mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);if (mProfile) {Debug.startMethodTracing("ViewAncestor");}performTraversals(); //关键方法if (mProfile) {Debug.stopMethodTracing();mProfile = false;}}}

大家在代码中可以看到 performTraversals() 就代表你越来越接近布局的绘制了,下节我们继续分解 performTraversals()

Activity启动流程源码分析-浅析生命周期函数相关推荐

  1. Activity启动流程源码分析(基于Android N)

    Activity启动流程源码分析 一个Activity启动分为两种启动方式,一种是从Launcher界面上的图标点击启动,另一种是从一个Activity中设置按钮点击启动另外一个Activity.这里 ...

  2. SpringBoot2 | SpringBoot启动流程源码分析(一)

    首页 博客 专栏·视频 下载 论坛 问答 代码 直播 能力认证 高校 会员中心 收藏 动态 消息 创作中心 SpringBoot2 | SpringBoot启动流程源码分析(一) 置顶 张书康 201 ...

  3. DataNode启动流程源码分析

    我们都知道在Hadoop hdfs文件系统中,Datanode是负责hdfs文件对应的数据块存储管理的组件,其会在启动时向NameNode汇报其上拥有的数据块,以及周期性心跳并接收来自NameNode ...

  4. Activity启动过程源码分析

    老罗的Android系统源码分析讲的很不错,网上有很不同层面多源码分析.了解细节,还是自己看源码最直接.个人并没有透彻的研究过Android系统,这一系列的博客就当是读Android源码笔记了.有不对 ...

  5. SpringBoot配置外部Tomcat项目启动流程源码分析(下)

    前言 SpringBoot应用默认以Jar包方式并且使用内置Servlet容器(默认Tomcat),该种方式虽然简单但是默认不支持JSP并且优化容器比较复杂.故而我们可以使用习惯的外置Tomcat方式 ...

  6. Spark On YARN启动流程源码分析

    1.spark-submit入口介绍 一般的spark作业都是通过命令行spark-submit相关的指令来进行提交,使用--master yarn来指定提交到对应的yarn集群上,如下: ./bin ...

  7. Android11 SystemUI启动流程源码分析(一)——SystemUIApplication的创建

    Manifest入口 <applicationandroid:name=".SystemUIApplication"... ...android:appComponentFa ...

  8. Service通过onBind跨进程启动流程源码探究

    根据<Activity跨进程启动流程源码探究>我们可以清楚以下几点: 1)Context的通用实现是在ContextIml这个类中 2)Activity的启动过程需要借助ActivityM ...

  9. 二次开发:flowable审批流程实践与创建流程源码分析

    二次开发:flowable审批流程实践与创建流程源码分析 上一篇已经描述了基于开源项目https://doc.iocoder.cn/的flowable的快速开发,创建了一个租户,创建了用户和相应的岗位 ...

最新文章

  1. shell执行mysql命令
  2. C#利用Graphics类绘制进阶--绘制条形码Code128
  3. GET和POST有什么区别?及为什么网上的多数答案都是错的。
  4. mysql 5.5.55_MySQL系列(5)
  5. 扫地机器人“离家出走”的真实原因找到了:差个自动驾驶算法
  6. openstack学习笔记三 创建第一个实例
  7. C++ Primer 5th笔记(chap 14 重载运算和类型转换)重载运算概述
  8. 160个Crackme003之4C大法详解
  9. 【C++】运算符重载
  10. python语言编程中的保留字_Python语言程序设计整理
  11. java math max_Java Math类静态double max(double d1,double d2)示例
  12. 一大波人气博主袭来,现场直播华为全联接2020!
  13. 生产力提升! 自己动手自定义Visual Studio 2019的 类创建模板,制作简易版Vsix安装包
  14. WX计数器统计器使用教程
  15. php多人聊天室系统,PHP打造多人在线聊天室[一]
  16. 足球大数据预测胜平负、走地之人工智能算法现状与改进措施
  17. Learning to Count via Unbalanced Optimal Transport
  18. Work with Hans
  19. iPhoneXS Max 获取UDID
  20. 怎么降低软件开发成本风险_降低开发人员成本的5种方法

热门文章

  1. MIS系统开发利器,快速的字典录入解决方案,另类的、可管理的.NET DataWindow
  2. Excel中如何快速输入☑和☒
  3. JavaScript实现数字金额小写转大写
  4. 数据库原理--概念模型
  5. 串口转IAP然后到APP
  6. esxi 7.0 封装瑞昱网卡驱动_虚拟机(ESXi)下硬盘性能的探索
  7. Js实现购物车加减,价格计算等功能
  8. iOS开发------简单实现图片多选功能(Photos.framework篇)
  9. 快端午了,用Python画一盘粽子送给你
  10. 云会议是什么?如何提升云会议的协同能力?