android View生命周期

Posted android超级兵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android View生命周期相关的知识,希望对你有一定的参考价值。

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

android 甲骨文之 View 生命周期

前言: 最近在写materialDesign系列的博客,上一篇介绍了NestedScrollView的源码分析,本来计划本篇为CoordinatorLayout源码分析,但是CoordinatorLayout涉及到了View的生命周期的知识,我又不想潦草的糊弄,所以那就穿插一篇View的生命周期吧

源码基于: android-30

整体流程

先来看看整体流程,然后再深入源码!

  • 第一次加载:

szj_TestActivity: activity onCreate start # activity onCreate 开始
szj_TestLifeView: onFinishInflate
szj_TestActivity: activity onCreate end # activity onCreate 结束
szj_TestActivity: activity onStart
szj_TestActivity: activity onResume
szj_TestLifeView: onAttachedToWindow
szj_TestLifeView: onWindowVisibilityChanged visibility:VISIBLE
szj_TestLifeView: onVisibilityChanged:changedView:TestLifeView visibility:VISIBLE
szj_TestLifeView: onMeasure
szj_TestLifeView: onMeasure
szj_TestLifeView: onSizeChanged w:300 h:300 oldW0: oldH0
szj_TestLifeView: onLayout changed:true left:0 top:0 right300: bottom300
szj_TestLifeView: onDraw
szj_TestLifeView: onWindowFocusChanged hasWindowFocus:true

  • 切换到后台:

szj_TestActivity: activity onPause
szj_TestLifeView: onWindowVisibilityChanged visibility:GONE
szj_TestLifeView: onWindowFocusChanged hasWindowFocus:false
szj_TestActivity: activity onStop
szj_TestLifeView: onVisibilityChanged:changedView:DecorView visibility:INVISIBLE

  • 切换到前台:

szj_TestLifeView: onWindowVisibilityChanged visibility:INVISIBLE
szj_TestActivity: activity onRestart
szj_TestActivity: activity onStart
szj_TestActivity: activity onResume
szj_TestLifeView: onVisibilityChanged:changedView:DecorView visibility:VISIBLE
szj_TestLifeView: onWindowVisibilityChanged visibility:VISIBLE
szj_TestLifeView: onDraw
szj_TestLifeView: onWindowFocusChanged hasWindowFocus:true

  • 销毁 view :

szj_TestActivity: activity onPause
szj_TestLifeView: onWindowFocusChanged hasWindowFocus:false
szj_TestLifeView: onWindowVisibilityChanged visibility:GONE
szj_TestActivity: activity onStop
szj_TestLifeView: onVisibilityChanged:changedView:DecorView visibility:INVISIBLE
szj_TestActivity: activity onDestroy
szj_TestLifeView: onDetachedFromWindow

流程图:

tips:

onCreate#setContentView() startonCreate#setContentView() end 指的是这样

源码分析开始

framework的源码,我愿称之为终极甲骨文,我也没怎么看过,只知道个大概,所以这里就从android段的源码开始 (后续会补上)

activity启动过程中,会通过AMS调用到 ActivityThread.handleLaunchActivity()ActivityThread.handleResumeActivity() ,那么就从这两个方法开始!

ActivityThread#handleLaunchActivity()

# ActivityThread.java
  
public Activity handleLaunchActivity(ActivityClientRecord r,
                                     PendingTransactionActions pendingActions, Intent customIntent) 

  // szj 初始化 windowManagerGlobal 
  WindowManagerGlobal.initialize();

  // szj 
  final Activity a = performLaunchActivity(r, customIntent);
  return a;


 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) 
        // szj 创建 activity 的上下文
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
     try 
       java.lang.ClassLoader cl = appContext.getClassLoader();
       // 通过反射创建 activity 的实例
       activity = mInstrumentation.newActivity(
         cl, component.getClassName(), r.intent);
       
        // 调用 activity#attach 创建 PhoneWindow 等
       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,
                       r.assistToken);
           
        // szj 分发 onCreate() 事件
         mInstrumentation.callActivityOnCreate(activity, r.state);
        catch(e)...
 

Tips:

  • mInstrumentation: 负责调用Activity和Application生命周期。 在 ActivityThread#main()方法中创建

  • Activity#attach() 创建 PhoneWindow()

所以这里需要关心的就是 :

  • 初始化:WindowManagerGlobal.initialize();
  • 初始化:PhoneWindow()

分发#Activity#onCreate()事件:

# Instrumentation.java

 public void callActivityOnCreate(Activity activity, Bundle icicle) 
  		 // 分发onCreate事件
       activity.performCreate(icicle);
    
# Activity.java

final void performCreate(Bundle icicle) 
  performCreate(icicle, null);


 final void performCreate(Bundle icicle, PersistableBundle persistentState) 
   
   if (persistentState != null) 
     onCreate(icicle, persistentState);
    else 
     // 出发onCreate() 事件
     onCreate(icicle);
   
 

tips: 所有Activity的生命周期都是通过Instrumentation调用callActivityOnXXX() 来调用的,比如这里的callActivityOnCreate(),以及 下面介绍的callActivityOnResume()

ActivityThread#handleResumeActivity()

# ActivityThread.java
  
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                 String reason) 
   // ...
   // 分发 onResume 事件 
   final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
   final Activity a = r.activity;
   if (r.window == null && !a.mFinished && willBeVisible) 

       // 绑定window
       r.window = r.activity.getWindow();

       // 调用 PhoneWindow.getDecorView() 返回 DecorView
       View decor = r.window.getDecorView();
   		
      // szj ViewManager
      ViewManager wm = a.getWindowManager();
     
       // 返回 w = LayoutParams.MATCH_PARENT, h = LayoutParams.MATCH_PARENT
      WindowManager.LayoutParams l = r.window.getAttributes();
   
     if (!a.mWindowAdded) 
       a.mWindowAdded = true;
       // 将 DecorView 添加到 window 上 (设置activity根视图) 关键!
       wm.addView(decor, l);
     
   

分发 onResume 事件:

wm.addView( decor , l )方法上参数为:

  • @param decor : DecorView(FrameLayout)

  • @param l : LayoutOarams(width: MATCH_PARENT, height: MATCH_PARENT)

这里的 wm 是一个接口,实现类为 WindowManager, WindowManager 也是一个接口,最终实现类为 WindowManagerImpl

最终执行到 WindowManagerImpl$addView()方法上

# WindowManagerImpl.java
  
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) 
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    	
# WindowManagerGlobal.java

// @param view: DecorView
// @param params: w:match_parent h:match_parent
// @param parentWindow: PhoneWindow
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) 
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        ViewRootImpl root;
  
  		   //szj 实例化一个 ViewRootImpl
         root = new ViewRootImpl(view.getContext(), display);
  
        try 
          //szj 将 ViewRootImpl 与 DecorView 关联到一起
          root.setView(view, wparams, panelParentView, userId);
         catch (RuntimeException e)  ... 
 

调用到ViewRootImpl#setView()

# ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) 
       if (mView == null) 
           // 将 DecorView 绑定到 ViewRootImpl.mView 属性上
           mView = view;
  
          ....
          requestLayout();
          ...
       



@Override
public void requestLayout() 
    if (!mHandlingLayoutInLayoutRequest) 
      // 检查是否在 UI线程
      checkThread();
      // 执行到这里
      scheduleTraversals();
    



void scheduleTraversals() 
    if (!mTraversalScheduled) 
        mTraversalScheduled = true;
        // szj handler 同步屏障
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // 将 UI 绘制任务发送到 Choreographer,回调触发 mTraversalRunnable,执行绘制操作
        mChoreographer.postCallback(
          Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
       ...
    

# ViewRootImpl.java

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

final class TraversalRunnable implements Runnable 
    @Override
    public void run() 
      // szj 执行任务
      doTraversal();
    


 // szj 同步屏障执行到这里
void doTraversal() 
    if (mTraversalScheduled) 
        mTraversalScheduled = false;
        // 移除同步屏障
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

        // szj view 开始测量 / 绘制 / 布局 真正执行生命周期
        performTraversals();

        ..
    

private void performTraversals() 
 	  final View host = mView;

    /*
     * TODO 调用:
     *      1.View#onAttachedToWindow()  当 view 绑定 window 的时候
     *      2.View#onWindowVisibilityChanged() 当w indow 可见的时候调用
     *      3.View#onVisibilityChanged() 当 判断view是否隐藏时候调用,如果view.visibility = GONE 那么不执行测量绘制流程!
     */
    if (mFirst) 
      host.dispatchAttachedToWindow(mAttachInfo, 0);
    
  
    if (viewVisibilityChanged) 
        // 当 window 可见的时候调用 会调用View#onWindowVisibilityChanged()
				host.dispatchWindowVisibilityChanged(viewVisibility);
    
  
    if (layoutRequested) 
      
       // szj 执行这里 measureHierarchy 在 measureHierarchy() 中会多次调用 performMeasure() 来分发 onMeasure() 事件
       windowSizeMayChange |= measureHierarchy(host, lp, res,
                    desiredWindowWidth, desiredWindowHeight);
    
  
    if (!mStopped || mReportNextDraw) 
      if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                        || mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
                        updatedConfiguration) 
          // 分发 onMeasure()事件
          performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
      
      
      if (measureAgain) 
        //   分发 onMeasure()事件
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
      
    
  
    if (didLayout) 
        // szjperformLayout 开始布局 分发 onLayout() 事件
        performLayout(lp, mWidth, mHeight);
    
  
    if (!cancelDraw) 
        if (mPendingTransitions != null && mPendingTransitions.size() > 0) 
            for (int i = 0; i < mPendingTransitions.size(); ++i) 
              mPendingTransitions.get(i).startChangingAnimations();
            
            mPendingTransitions.clear();
        

        // szjperformDraw 开始绘制 分发 onDraw() 事件 
        performDraw();
    else 
      if (isViewVisible) 
        // 递归再次尝试 
        scheduleTraversals();
       ...
    

重点:

  • View#dispatchAttachedToWindow(mAttachInfo, 0);
  • View#dispatchWindowVisibilityChanged(viewVisibility);
  • ViewRootImpl#measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight);
  • ViewRootImpl#performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
  • ViewRootImpl#performLayout(lp, mWidth, mHeight);
  • ViewRootImpl#performDraw();

View#dispatchAttachedToWindow(mAttachInfo, 0);

# View.java
  
void dispatchAttachedToWindow(AttachInfo info, int visibility) 
  	// View 生命周期1: 当 view 绑定 window 的时候调用
  	onAttachedToWindow();
  
    int vis = info.mWindowVisibility;
    if (vis != GONE) 
      // View 生命周期2: 当 window 可见的时候调用
      onWindowVisibilityChanged(vis);
        ...
    
    // View 生命周期3: 当判断view是否可见的时候调用 android:visibility="XXX"
   	onVisibilityChanged(this, visibility);

这里需要注意的是会执行三个生命周期方法:

  • onAttachedToWindow(); 当 view 绑定 window 的时候调用

  • onWindowVisibilityChanged(int); 当 window 可见的时候调用

  • onVisibilityChanged(View, int); 当判断view是否可见的时候调用 android:visibility=“XXX”

View#dispatchWindowVisibilityChanged(viewVisibility);

# View.java
  
public void dispatchWindowVisibilityChanged(@Visibility int visibility) 
        onWindowVisibilityChanged(visibility);
    

这个方法比较简单,直接就是当window 试图发生变化的时候调用

ViewRootImpl#measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight); 与 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

这里measureHierarchy() 最终会调用到 performMeasure()上,所以这两个就连起来聊了

private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
                                 final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) 
    if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) 
        if (baseSize != 0 && desiredWindowWidth > baseSize) 
            childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
                childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
         			  // 分发 onMeasure() 事件 
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
          if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) 
                    goodMeasure = true;
           else 
                // 分发 onMeasure() 事件 
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
          
        
    

# View.java

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) 
        if (mView == null) 
            return;
        
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try 
            // 分发view.measure事件
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
         finally 
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        
    

public final void measure(int widthMeasureSpec, int heightMeasureSpec) 
  if (forceLayout || needsLayout) 
    if (cacheIndex < 0 || sIgnoreMeasureCache) 
      // 开始测量
       onMeasure(widthMeasureSpec, heightMeasureSpec);
    
  


// 测量
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
  // 默认测量 
  setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                       getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));


// 默认测量 
public static int getDefaultSize(int size, int measureSpec) 
        int result = size;
        // 测量模式
        int specMode = MeasureSpec.getMode(measureSpec);
        // 测量大小
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) 
            // 未指定 即未限制 View 的大小 (常在 ScrollView 中使用,上一篇 NestedScrollView 就用到了!)
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;

            // 最大值
        case MeasureSpec.AT_MOST:
            // 具体值
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        
        return result;
    

这里 通过 performMeasure 执行到了View#measure --> onMeasure()这里需要注意的是 onMeasure 会多次测量,至少 2 次

测量模式就不过多介绍了,既然能看到这里,测量模式必然是都懂的!

ViewRootImpl#performLayout(lp, mWidth, mHeight);

# ViewRootImpl.java

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) 
  	 final View host = mView;
     host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());     

# View.java
  
public void layout(int l, int t, int r, int b) 
  // szj setOpticalFrame() / setFrame() 重点 调用 onSizeChanged() 方法
  	boolean changed = isLayoutModeOptical(mParent) ?
                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
  if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) 
            // szj 重点() 用来确定View的布局位置
            onLayout(changed, l, t, r, b);
    ...
  


深入懂得android view 生命周期

android中view的生命周期

android View生命周期

深入理解android view 生命周期

Android自定义View探索—生命周期

Android View生命周期