activity生命周期-进阶版(除了onCreate...onDestroy这些还有什么?)

来源:互联网 发布:ubuntu 17.04 安装qq 编辑:程序博客网 时间:2024/05/22 12:03

时隔两年,我对于activity的生命周期非但未变得清晰,反而越来越疑惑。除了普通生命周期方法:onStart(),onRestart(),onCreate(),onResume(),onPause(),onStop(),onDestroy()这些,其实activity启动时,还有一些隐藏的,系统一定会调用的方法。

事实上,一些优秀的开源项目会重写这些方法,完成一些必要的操作,而我在看到这些方法,除了牛掰,大概看的懂之外,再无其他的感受了。

以下方法,也是系统一定会调用的方法:
onApplyThemeResource(Theme theme, int resid, boolean first)
onContentChanged()
onPostCreate()
onPostResume()
onAttachedToWindow()
onWindowFocusChanged(boolean hasFocus)
onDetachedFromWindow()

以下几个问题是一定要搞清楚的,为了我的生命周期大业:
这些方法和生命周期夹杂在一起,哪个先,哪个后?当对话框弹出来,会调用哪些?当应用进入后台,会调用哪些?
哪些获得的window是不为空的?
哪些进行数据处理,会对界面显示造成影响?(黑白屏,无焦点)
哪些可以对view进行初始化?
哪些可以获得控件的尺寸?

我想,这非常重要,此后还会特别关注view的生命周期。此次主要对以上问题进行测试,并进行结果记录。

1.执行顺序

启动执行顺序:(注意onPostCreate()未被调用)
onApplyThemeResource()
onContentChanged()
onCreate()
onStart()
onResume()
onPostResume()
onAttachedToWindow()
onWindowFocusChanged()

dialog弹出,关闭:
都只调用onWindowFocusChanged,额,onPause呢?难道7.0不用了?换个手机再试试。好吧,现在很多手机在dialog启动的时候不会onPause了,就调用了onWindowFocusChanged,看来课本什么的也不一定靠谱。或许有些型号依旧满足失去焦点会调用onPause,但我试的小米,红米都不会。

退出activity:
onPause()
onWindowFocusChanged()
onStop()
onDestroy()
onDetachedFromWindow()

注意,退出时onDetachedFromWindow()是在onDestroy()之后调用的。

转屏:
onPause()
onStop()
onDestroy()
onDetachedFromWindow()
onApplyThemeResource()
onContentChanged()
onCreate()
onStart()
onResume()
onPostResume()
onAttachedToWindow()
onWindowFocusChanged()
网上看到其他人测试会调用到onPostCreate(),但是我的真的没有,看来这个方法并不完全靠谱,决定弃疗。

2.哪些window不为空?

好吧,getWindow()都不为空,那么onAttachToWindow()的意义何在?试试getDecorView,终于有用了,测试结果:
onApplyThemeResource()DecorView@9f4f736[]
onContentChanged()DecorView@9f4f736[]
onCreate()DecorView@9f4f736[]
onStart()DecorView@9f4f736[]
onResume()DecorView@9f4f736[]
onPostResume()DecorView@9f4f736[]
onAttachedToWindow()DecorView@9f4f736[LifecycleActivity]
onWindowFocusChanged()DecorView@9f4f736[LifecycleActivity]
onPause()DecorView@9f4f736[LifecycleActivity]
onWindowFocusChanged()DecorView@9f4f736[LifecycleActivity]
onStop()DecorView@9f4f736[LifecycleActivity]
onDestroy()DecorView@9f4f736[LifecycleActivity]
onDetachedFromWindow()DecorView@9f4f736[LifecycleActivity]

发现了么?方括号里面的是DectorView绑定的activity,可以看到,这个DctorView确实挺特殊,从onAttatchToWindow以后就一直和activity处于绑定状态,包括onDestroy

当需要获取状态栏,标题栏高度的时候,可以用它,我记得应用要截屏的时候,也有用到,这时候注意放在onAttachedToWindow了。

状态栏,标题栏

Rect frame = new Rect();  getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);  int statusBarHeight = frame.top;  Rect frame = new Rect();  getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);  int statusBarHeight = frame.top

屏幕截图:

public static Bitmap captureScreen(Activity activity) {      activity.getWindow().getDecorView().setDrawingCacheEnabled(true);      Bitmap bmp=activity.getWindow().getDecorView().getDrawingCache();      return bmp;  }  

3.对于略耗时的操作,哪些对界面有影响哪些没有?

我这里指的略耗时,并不是像网络请求这种的,而是循环次数较多,数据略庞大,这里用:

 for(int i = 0; i < 1000000; i++){            Log.e(TAG,"onPause()"+getWindow().getDecorView());        }

代替。

效果:
onStart()-黑屏卡死
onRestart()-卡死无黑屏
onResume()-黑屏卡死
onCreate()-黑屏卡死
onStop()-无影响
onPause()-黑屏卡死
onDestroy()-无影响
onApplyThemeResource()-黑屏卡死
onContentChanged()-黑屏卡死
onPostResume()-黑屏卡死
onAttachedToWindow()-黑屏卡死
onWindowFocusChanged()-无影响
onDetachedFromWindow()-无影响

可见启动过程中,唯一对于略多数据处理没有影响的就是onWindowFocusChanged(),关闭过程中,onStop(),onDestroy(),onDetachedFromWindow()无影响。让我略惊讶的是,onCreate方法中,进行这种处理也会卡死,如果这个数据降到100,对于卡死的方法效果会不同吗?

通过测试发现,其实那些卡死的在少量数据的情况下,或许会略卡顿,但是不会太明显,onCreate是一样的,卡顿效果略改善。所以对于少量数据处理,还是放在onCreate方法中更妥当一些。如果数据量略大,可考虑放在onAttachToWindow(),但是还有个问题,就是失去焦点时也会调用这个方法,需要添加一些条件判断。如果数据量庞大,还是放在异步中处理更妥善一些。

4.获取view,哪些为空?

onApplyThemeResource()null
onContentChanged()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……I. 0,0-0,0 #7f0c0060 app:id/btn_lifecycle_dialog}

onCreate()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……I. 0,0-0,0 #7f0c0060 app:id/btn_lifecycle_dialog}

onStart()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……I. 0,0-0,0 #7f0c0060 app:id/btn_lifecycle_dialog}

onResume()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……I. 0,0-0,0 #7f0c0060 app:id/btn_lifecycle_dialog}

onPostResume()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……I. 0,0-0,0 #7f0c0060 app:id/btn_lifecycle_dialog}

onAttachedToWindow()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……I. 0,0-0,0 #7f0c0060 app:id/btn_lifecycle_dialog}

onWindowFocusChanged()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……I. 0,0-600,240 #7f0c0060 app:id/btn_lifecycle_dialog}

onPause()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. …….. 0,0-600,240 #7f0c0060 app:id/btn_lifecycle_dialog}

onWindowFocusChanged()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. …….. 0,0-600,240 #7f0c0060 app:id/btn_lifecycle_dialog}

onStop()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. …….. 0,0-600,240 #7f0c0060 app:id/btn_lifecycle_dialog}

onDestroy()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. …….. 0,0-600,240 #7f0c0060 app:id/btn_lifecycle_dialog}

onDetachedFromWindow()android.support.v7.widget.AppCompatButton{227e6023 VFED..C. ……ID 0,0-600,240 #7f0c0060 app:id/btn_lifecycle_dialog}

可以看到,除了onApplyThemeResource都可以获取到view,不过应该不是每个都能对view进行操作吧,试试setText(),结果是,真的都可以!

5.控件尺寸:

当然onApplyThemeResource因为获得view为null不可以,就不试了,我这里简单粗暴,直接getWidth()获取控件宽度。
onContentChanged()0
nCreate()0
onStart()0
onResume()0
onPostResume()0
onAttachedToWindow()0
onWindowFocusChanged()600
onPause()600
onWindowFocusChanged()600
onStop()600
onDestroy()600
onDetachedFromWindow()600
可以看到,onWindowFocusChanged是创建过程中唯一可以获得正确的尺寸的。

总结

所实话,这次测试受益很大,尤其是dialog弹出那里,原来有些手机除了销毁已经不怎么用onPause了,这个方法既然在有的手机内不能作为失去焦点的依据,那么以后就要把onWindowFocusChanged(false)当做onPause用了。
说几点关键的:
onAttachedToWindow()-decorView开始不为空,可用于获取状态栏高度等,以后重写后我要把它变成onAttachedDecorView(),便于理解。
onWindowFocusChanged-true可以用来获取尺寸,以及略多的数据初始化,false可以当onPause用
onStart/onResume/onRestart这些还是不要随便用,可以用onWindowFocusChanged(true)代替,这个方法可以处理稍大些的数据,用户体验应该较好。重写时会将true的时候分到onStartDataDimen(),false时分到onPauseDataDimen(),容易记忆。

因为每次打开界面(包括打开dialog)onWindowFocusChanged,home键都会被调用,还可以用于作用于数据保存和恢复,放在intent里面就可以了:

 @Override    public void onWindowFocusChanged(boolean hasFocus) {//可以        super.onWindowFocusChanged(hasFocus);        Log.e(TAG,"onWindowFocusChanged()"+getIntent()+num);        if(hasFocus) {            num = getIntent().getIntExtra("num", 0);            boolean isFirst = getIntent().getBooleanExtra("isFirst",true);            if(isFirst){                num = 5;                getIntent().putExtra("isFirst",false);            }        }else            getIntent().putExtra("num",num);    }

这部分可以放到onCreate():

 boolean isFirst = getIntent().getBooleanExtra("isFirst",true);            if(isFirst){                num = 5;                getIntent().putExtra("isFirst",false);            }

比onCreate+onSaveInstance靠谱多了,哈哈,这个方法好万能啊,还不会卡顿。

ps:以前都是用post获取的宽高,自定义组件多了白屏就延时加载,呵呵,测过之后被自己蠢哭了T T.