Activity.onAttachedToWindow()

简介

首先看Window.Callback中关于onAttachedToWindow的介绍:

public abstract void onAttachedToWindow ()
Called when the window has been attached to the window manager. See View.onAttachedToWindow() for more information.

好吧,官方把我引导到了View中,那么恭敬不如从命,看View中怎么说:

protected void onAttachedToWindow ()
This is called when the view is attached to a window. At this point it has a Surface and will start drawing. Note that this function is guaranteed to be called beforeonDraw(android.graphics.Canvas), however it may be called any time before the first onDraw – including before or after onMeasure(int, int).

从API说明可知,当View附加到窗体时,也就是View和Window绑定时就会调用这个函数,此时将会有一个Surface进行绘图之类的逻辑。并且发现Window.CallBack是一个接口类,而且官方引导到了View中,那么可以大胆判断View实现了Window.CallBack的回调方法,那么View和Window之间的关系便可以有个初步猜测。下篇博客再具体讨论DecorView和Window之间的关系。

onAttachedToWindow在Activity整个生命周期中的位置。

将Activity各个生命周期打上log,然后看LogCat中的结果,可得出:

生命周期为 onCreate->onStart->onResume->onAttachedToWindow

找了张比较完整的activity生命周期图,印证了上面的结论
activity生命周期

为什么要在onAttachedToWindow中修改窗口尺寸?

为什么网上很多教程一定要在onAttachedToWindow()里修改高宽而不在onCreate中?
将代码放到onCreate中进行测试:

View view = getWindow().getDecorView();  
WindowManager.LayoutParams lp = (WindowManager.LayoutParams)view.getLayoutParams();  
lp.gravity = Gravity.CENTER;  
lp.width = (dm.widthPixels * 4) / 5;  
lp.height = (dm.widthPixels * 4) / 5;  
getWindowManager().updateViewLayout(view,lp); 

结果发现,lp.gravity = Gravity.CENTER 这行报了空指针异常,所以view.getLayoutParams()获取的LayoutParams是空,那么问题来了!为什么onCreate()中DecorView的LayoutParams是空而onAttachedToWindow()中就不为空?要搞清这个问题就要看DecorView在什么时候设置的LayoutParam。

public final class ActivityThread {    
        ......         
        final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {    
            ......    
            ActivityClientRecord r = performResumeActivity(token, clearHide);    

            if (r != null) {    
                final Activity a = r.activity;    
                ......    
                if (r.window == null && !a.mFinished && willBeVisible) {    
                    r.window = r.activity.getWindow(); // PhoneWindow   
                    View decor = r.window.getDecorView(); // PhoneWindow 中的DecorView 
                    decor.setVisibility(View.INVISIBLE);    
                    ViewManager wm = a.getWindowManager();    
                    WindowManager.LayoutParams l = r.window.getAttributes();    
                    a.mDecor = decor;    
                    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;    
                    ......    
                    if (a.mVisibleFromClient) {    
                        a.mWindowAdded = true;    
                        wm.addView(decor, l); // 给DecorView设置LayoutParam   
                    }    
                }          
                ......    
            }    
            ......    
        }              
        ......    
    }

原来在ActivityThread执行handleResumeActivity时就会为PhoneWindow中的DecorView设置LayoutParam,并且通过源码发现handleResumeActivity函数首先会执行performResumeActivity,此时会调用Activity的onResume()生命周期函数。看来只要在Activity的onResume生命周期后就能获取DecorView的LayoutParam,进而可以设置高度和宽度了。根据上面贴出的生命周期图,onResume()后面是onAttachedToWindow(),并且onAttachedToWindow只会调用一次,不会受用户操作行为影响。所以在onAttachedToWindow中进行窗口尺寸的修改再合适不过了。

总结

  • onAttachedToWindow运行在onResume之后;
  • DecorView的LayoutParams是在ActivityThread的handleResumeActivity中设置的,并且该函数会调用Activity的onResume生命周期,所以在onResume之后可以设置窗体尺寸;

参考文章

onAttachedToWindow()在整个Activity生命周期的位置及使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值