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

本文详细解析了Android Activity生命周期中onAttachedToWindow方法的位置及其作用,解释了为何要在该方法中修改窗口尺寸,通过源码分析深入理解DecorView LayoutParam的设置时机。

上篇博客实现圆角对话框样式的Activity中提到,若需实现圆角对话框Activity,需要在Activity的onAttachedToWindow()函数中做文章,那么就想问:

  • onAttachedToWindow在整个Activity的生命周期中占据什么位置?
  • 为什么要在onAttachedToWindow中修改窗口尺寸?

 

一、onAttachedToWindow在Activity生命周期中的位置

根据之前分析API的套路,看onAttachedToWindow在Android文档中怎样介绍。

首先看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

 然后通过Google找到了一张比较详细的Activity生命周期图,也印证了我们的实验结论。

详见http://staticfree.info/~steve/complete_android_fragment_lifecycle.svg

 

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

为什么网上很多教程一定要在onAttachedToWindow()里修改高宽而不在onCreate中?这个问题没人解答,那么我就将代码

  1. View view = getWindow().getDecorView();  
  2. WindowManager.LayoutParams lp = (WindowManager.LayoutParams)view.getLayoutParams();  
  3. lp.gravity = Gravity.CENTER;  
  4. lp.width = (dm.widthPixels * 4) / 5;  
  5. lp.height = (dm.widthPixels * 4) / 5;  
  6. getWindowManager().updateViewLayout(view,lp);  
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);

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

从博客Android应用窗口的视图对象的创建过程分析中发现源码

  1. public final class ActivityThread {    
  2.     ......    
  3.     
  4.     final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {    
  5.         ......    
  6.     
  7.         ActivityClientRecord r = performResumeActivity(token, clearHide);    
  8.     
  9.         if (r != null) {    
  10.             final Activity a = r.activity;    
  11.             ......    
  12.     
  13.             // If the window hasn't yet been added to the window manager,     
  14.             // and this guy didn't finish itself or start another activity,     
  15.             // then go ahead and add the window.     
  16.             boolean willBeVisible = !a.mStartedActivity;    
  17.             if (!willBeVisible) {    
  18.                 try {    
  19.                     willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(    
  20.                             a.getActivityToken());    
  21.                 } catch (RemoteException e) {    
  22.                 }    
  23.             }    
  24.             if (r.window == null && !a.mFinished && willBeVisible) {    
  25.                 r.window = r.activity.getWindow();    
  26.                 View decor = r.window.getDecorView();    
  27.                 decor.setVisibility(View.INVISIBLE);    
  28.                 ViewManager wm = a.getWindowManager();    
  29.                 WindowManager.LayoutParams l = r.window.getAttributes();    
  30.                 a.mDecor = decor;    
  31.                 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;    
  32.                 ......    
  33.                 if (a.mVisibleFromClient) {    
  34.                     a.mWindowAdded = true;    
  35.                     wm.addView(decor, l);    
  36.                 }    
  37.             }     
  38.     
  39.             ......    
  40.         }    
  41.     
  42.         ......    
  43.     }    
  44.       
  45.     ......    
  46. }    
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 the window hasn't yet been added to the window manager,  
            // and this guy didn't finish itself or start another activity,  
            // then go ahead and add the window.  
            boolean willBeVisible = !a.mStartedActivity;  
            if (!willBeVisible) {  
                try {  
                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(  
                            a.getActivityToken());  
                } catch (RemoteException e) {  
                }  
            }  
            if (r.window == null && !a.mFinished && willBeVisible) {  
                r.window = r.activity.getWindow();  
                View decor = r.window.getDecorView();  
                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);  
                }  
            }   
  
            ......  
        }  
  
        ......  
    }  
    
    ......  
}  

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

总结:

  • onAttachedToWindow运行在onResume之后;
  • DecorView的LayoutParams是在ActivityThread的handleResumeActivity中设置的,并且该函数会调用Activity的onResume生命周期,所以在onResume之后可以设置窗体尺寸;
DnaMan 是一款功能强大的综合性分子生物学软件,主要用于 序列分析、引物设计、多序列比对、进化树构建 等任务,广泛应用于分子生物学、生物信息学和遗传学研究。以下是关于 DnaMan 的详细介绍:1. 主要功能(1)序列分析与比对多序列比对(MSA):支持 ClustalW、Muscle 等算法,可视化比对结果。序列编辑:提供序列修剪、反向互补、翻译(DNA→Protein)等功能。同源性分析:计算序列相似性,识别保守区域。(2)引物设计PCR 引物设计:自动优化引物 Tm 值、GC 含量、二聚体等参数。探针设计:适用于 qPCR、FISH 等实验。限制性酶切位点分析:帮助选择合适的酶切位点用于克隆实验。(3)进化分析系统发育树构建:支持 NJ(邻接法)、ML(最大似然法)、MP(最大简约法) 等算法。进化树可视化:可调整分支、颜色、标签等,导出高质量图片。(4)其他实用功能开放阅读框(ORF)预测:识别基因编码区。蛋白质二级结构预测:如 α-螺旋、β-折叠分析。SNP 分析:检测单核苷酸多态性位点。2. 与 Primer Premier 5.0 的比较功能DnaManPrimer Premier 5.0主要用途多序列比对、进化分析、引物设计专注于 PCR 引物设计引物设计支持 PCR、qPCR、探针设计主要针对常规 PCR 引物优化多序列比对支持(ClustalW、Muscle)不支持进化树构建支持(NJ、ML、MP 方法)不支持序列编辑提供翻译、反向互补等工具功能较少用户界面较复杂,适合高级用户更简洁,适合初学者适用场景:如果只需要 PCR 引物设计,Primer Premier 5.0 更简单高效。如果需要 多序列比对、进化分析、ORF 预测等综合功能,Dn
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值