Android 探究View onAttachedToWindow 触发时机

网友投稿 1075 2022-11-19

Android 探究View onAttachedToWindow 触发时机

Android 探究View onAttachedToWindow 触发时机

文章目录

​​生命周期观察​​​​源码探究​​​​当一个view 被 add 的时候​​​​Activity onAttachedToWindow 是怎么触发的?​​​​OnAttachStateChangeListener​​​​在 `onAttachedToWindow` 能获取到 View 的宽高吗?​​​​当子view 被 add 的时候,会触发`View`树上其他`View`回调 `onAttachedToWindow` 吗?​​

生命周期观察

​​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​​

生命周期回调:

D/yu--: Activity onCreateD/yu--: Activity onResumeD/yu--: Activity onAttachedToWindowD/yu--: View onAttachedToWindowD/yu--: Activity onPauseD/yu--: Activity onStopD/yu--: Activity onDestroyD/yu--: View onDetachedFromWindowD/yu--: Activity

从回调的结果来看:

1、Activity onResume 之后回调 onAttachedToWindow2、Activity onDestroy 之后回调 onDetachedFromWindow3、Activity 的 onAttachedToWindow 回调之后,才会回调 view 的 onAttachedToWindow4、View onDetachedFromWindow 回调之后,才会回调 Activity onDetachedFromWindow

源码探究

当 ​​Activity​​​ 发生 ​​resume ​​​的时候,实际上是 ​​ActivityThread​​​ 的 ​​handleResumeActivity()​​ 被调用。

​​performResumeActivity​​​方法,会执行 ​​activity​​​ 的 ​​onResume​​ 方法。

​​WindowManagerImpl.java​​

这里的 ​​mGlobal​​ 就是 ​​WindowManagerGlobal​​ 类

我们看 ​​WindowManagerGlobal​​​ 的 ​​addView​​ 方法

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

回到正题,继续看 ​​ViewRootImpl​​​ 的 ​​requestLayout() ​​

​​scheduleTraversals() ​​​ 后续会执行 ​​doTraversal();​​

精简代码如下:

调用 ​​host.dispatchAttachedToWindow​​​ 方法,从逻辑中我们发现 host 其实就是 ​​DecorView​​ 。

所以就相当于 ​​DecorView.dispatchAttachedToWindow ​​

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

所以我们直接看 ​​ViewGroup​​​ 的 ​​dispatchAttachedToWindow​​ 方法。

​​ViewGroup​​​ 的 ​​dispatchAttachedToWindow​​​ 方法 ,首先会调用 ​​super.dispatchAttachedToWindow​​​,实际上是回调当前 ​​ViewGroup​​​ 的 ​​onAttachedToWindow ​​。

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

发现​​ View​​​ 的 ​​dispatchAttachedToWindow​​​ 会调用 ​​onAttachedToWindow ​​。

到此 ,​​onAttachedToWindow​​ 已经分析完。

当一个view 被 add 的时候

我们先从 ​​ViewGroup​​​ 的 ​​addView​​ 说起。

会调用当前 ​​ViewGroup​​​ 的 ​​requestLayout() ​​

通过递归调用,会逐级调用 parent 的 ​​requestLayout() ​​​ ,最终会走到 ​​DecorView ​​​ 的 ​​requestLayout() ​​

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

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

Activity onAttachedToWindow 是怎么触发的?

首先,我们来看看 ​​Activity​​​ 的 ​​onAttachedToWindow​​ 长什么样子的?

​​Activity​​​ 实现了 ​​Window.Callback ​​​, 并且实现了 ​​onAttachedToWindow​​​ 、 ​​onDetachedFromWindow​​

代码如下:

看 ​​Activity​​​ 的 ​​attach​​​ 方法,调用了 ​​ mWindow.setCallback(this)​​

​​mWindow​​​ 是 ​​PhoneWindow​​​ , 看看 ​​PhoneWindow​​​ 的 ​​setCallback​​

到这里我们基本明白了,​​Activity​​​ 的 ​​onAttachedToWindow​​ 是什么。

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

看看 ​​DecorView​​​ 的 ​​onAttachedToWindow​​ 的方法。

首先​​DecorView​​​ 的​​onAttachedToWindow​​ 会调用然后​​callback​​​ 的​​onAttachedToWindow​​ 会被调用

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

结论:

​​Activity ​​​的​​onAttachedToWindow​​​ 在​​DecorView​​​ 的​​onAttachedToWindow​​ 被调用时触发

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 不会触发。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Hello Playwright:(7)模拟键盘和鼠标
下一篇:spring boot 动态生成接口实现类的场景分析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~