Android 探究View onAttachedToWindow 触发时机

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/125607542
本文出自【赵彦军的博客】

生命周期观察

Activity

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Log.d("yu--", "Activity onCreate")
    }

    override fun onResume() {
        super.onResume()
        Log.d("yu--", "Activity onResume")
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        Log.d("yu--", "Activity onAttachedToWindow")
    }

    override fun onPause() {
        super.onPause()
        Log.d("yu--", "Activity onPause")
    }


    override fun onStop() {
        super.onStop()
        Log.d("yu--", "Activity onStop")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("yu--", "Activity onDestroy")
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        Log.d("yu--", "Activity onDetachedFromWindow")
    }

}

MyView

public class MyView extends View {

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.myapplication.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

生命周期回调:

D/yu--: Activity onCreate
D/yu--: Activity onResume
D/yu--: Activity onAttachedToWindow
D/yu--: View onAttachedToWindow
D/yu--: Activity onPause
D/yu--: Activity onStop
D/yu--: Activity onDestroy
D/yu--: View onDetachedFromWindow
D/yu--: Activity onDetachedFromWindow

在这里插入图片描述

从回调的结果来看:

  • 1、Activity onResume 之后回调 onAttachedToWindow
  • 2、Activity onDestroy 之后回调 onDetachedFromWindow
  • 3、Activity 的 onAttachedToWindow 回调之后,才会回调 view 的 onAttachedToWindow
  • 4、View onDetachedFromWindow 回调之后,才会回调 Activity onDetachedFromWindow

源码探究

Activity 发生 resume 的时候,实际上是 ActivityThreadhandleResumeActivity() 被调用。

performResumeActivity方法,会执行 activityonResume 方法。

在这里插入图片描述

WindowManagerImpl.java
在这里插入图片描述
这里的 mGlobal 就是 WindowManagerGlobal

我们看 WindowManagerGlobaladdView 方法

在这里插入图片描述

也就是说 , WindowManagerGlobal 的 addView 方法 ,创建了 ViewRootImpl , 然后建立 DecorView 和 ViewRootImpl 绑定关系。

回到正题,继续看 ViewRootImplrequestLayout()

在这里插入图片描述
scheduleTraversals() 后续会执行 doTraversal();

在这里插入图片描述

精简代码如下:

在这里插入图片描述
调用 host.dispatchAttachedToWindow 方法,从逻辑中我们发现 host 其实就是 DecorView

所以就相当于 DecorView.dispatchAttachedToWindow

因为 DecorView 也是一个 ViewGroup ,并且没有覆写 dispatchAttachedToWindow 方法。

所以我们直接看 ViewGroupdispatchAttachedToWindow 方法。

在这里插入图片描述

ViewGroupdispatchAttachedToWindow 方法 ,首先会调用 super.dispatchAttachedToWindow,实际上是回调当前 ViewGrouponAttachedToWindow

然后遍历 子view , 然后调用 child.dispatchAttachedToWindow

在这里插入图片描述

发现 ViewdispatchAttachedToWindow 会调用 onAttachedToWindow

到此 ,onAttachedToWindow 已经分析完。

当一个view 被 add 的时候

我们先从 ViewGroupaddView 说起。

会调用当前 ViewGrouprequestLayout()

在这里插入图片描述
通过递归调用,会逐级调用 parent 的 requestLayout() ,最终会走到 DecorView requestLayout()

因为 DecorView 的 parent 是 ViewRootImpl ,所以最终会走ViewRootImpl 调用 requestLayout()

下面的逻辑,我们就不分析了,和上面分析的一致。

Activity onAttachedToWindow 是怎么触发的?

首先,我们来看看 ActivityonAttachedToWindow 长什么样子的?

Activity 实现了 Window.Callback , 并且实现了 onAttachedToWindowonDetachedFromWindow

代码如下:

在这里插入图片描述
在这里插入图片描述

Activityattach 方法,调用了 mWindow.setCallback(this)

在这里插入图片描述
mWindowPhoneWindow , 看看 PhoneWindowsetCallback

在这里插入图片描述
到这里我们基本明白了,ActivityonAttachedToWindow 是什么。

剩下的,我们只要知道 window.mcallback 接口实例,在什么情况下会被调用,就能知道触发时机了。

看看 DecorViewonAttachedToWindow 的方法。
在这里插入图片描述

  • 首先 DecorViewonAttachedToWindow 会调用
  • 然后 callbackonAttachedToWindow 会被调用

这个 callback 是 在 Activity 中实现的的接口 , 所以 Activity onAttachedToWindow 就会被调用

结论:

  • Activity onAttachedToWindowDecorViewonAttachedToWindow 被调用时触发

OnAttachStateChangeListener

dispatchAttachedToWindow 的代码中,我们发现 除了 onAttachedToWindow 方法会执行外,OnAttachStateChangeListener 也会回调,mOnAttachStateChangeListeners 是一个集合,可以有多个 Listener

在这里插入图片描述
使用如下:

public class MyView extends View {

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
            @Override
            public void onViewAttachedToWindow(View v) {

            }

            @Override
            public void onViewDetachedFromWindow(View v) {

            }
        });
    }

}

onAttachedToWindow 能获取到 View 的宽高吗?

答案:不能,因为 onAttachedToWindow 在回调时,还没有 measure , layout

在这里插入图片描述

当子view 被 add 的时候,会触发View树上其他View回调 onAttachedToWindow 吗?

答案:不会,只会触发当前子view 的 onAttachedToWindow 被回调,其他View 不会触发。

在这里插入图片描述

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值