• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Android 探究View onAttachedToWindow 触发时机

武飞扬头像
赵彦军
帮助1

转载请标明出处: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 不会触发。

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfahaa
系列文章
更多 icon
同类精品
更多 icon
继续加载