这篇文章总结一下Android里面那些常用组件的生命周期,以及在项目中的一些简单应用。
Activity
Activity
的生命周期
说起Activity
的生命周期,很多人都会马上想起下面这张图:
(不错,这是一个已经烂大街的问题。不过我是总结给自己看的=。=)
我写了一个例子观察不同的动作对生命周期的影响:
Activity
首次启动:LifeCycle1Activity: onCreate LifeCycle1Activity: onStart LifeCycle1Activity: onResume
按下Home键:
LifeCycle1Activity: onPause LifeCycle1Activity: onStop
再次打开app:
LifeCycle1Activity: onRestart LifeCycle1Activity: onStart LifeCycle1Activity: onResume
跳转到其他
Activity
:LifeCycle1Activity: onPause LifeCycle2Activity: onCreate LifeCycle2Activity: onStart LifeCycle2Activity: onResume LifeCycle1Activity: onStop
从其他
Activity
返回:LifeCycle2Activity: onPause LifeCycle1Activity: onRestart LifeCycle1Activity: onStart LifeCycle1Activity: onResume LifeCycle2Activity: onStop LifeCycle2Activity: onDestroy
Activity
销毁:LifeCycle1Activity: onPause LifeCycle1Activity: onStop LifeCycle1Activity: onDestroy
切换横竖屏:
LifeCycle1Activity: onPause LifeCycle1Activity: onStop LifeCycle1Activity: onDestroy LifeCycle1Activity: onCreate LifeCycle1Activity: onStart LifeCycle1Activity: onResume
和生命周期相关的动作基本就是上面这些了。现在对照上面那张图以及这些Log,可以总结出以下几点:
- 当一个
Activity
创建并出现在屏幕中时,一定要经历onStart()
、onResume()
两个函数,只有做完onResume()
这个动作,Activity
才会可见; - 当
Activity
退到后台时(按home键或切换Activity
),一定要经过onPause()
、onStop()
两个动作。经过onPause()
这个动作,Activity
就已经不可见了,这个时候其他组件(如其他Activity
)会开始自己的创建绘制工作,等屏幕上面的其他组件绘制完成并覆盖原Activity
后,原Activity
才会调用onStop()
方法; - 当
Activity
从后台变为可见时,一定会经过onRestart()
、onStart()
和onResume()
三个动作,onResume()
之后Activity
才变得可见; - 切换横竖屏会导致
Activity
销毁并重建。
<br>
Activity
与Fragment
生命周期比较
由于Fragment
是要依附Activity
才能存在的,所以把Fragment
和Activity
放在一起对比,下面的View
同理。
说实话,Fragment
是我不怎么喜欢的组件(因为实在太复杂),但既然Google推荐,我们还是总结一下:
有了上面这张图,再结合Activity
的生命周期,基本就可以梳理完Fragment
的生命周期问题了。
这里主要总结一下同一个Activity
内不同Fragment
创建或替换时,生命周期的变化。
同一个
Activity
内同时创建两个Fragment
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class LifeCycle2Activity extends FragmentActivity {
MyFragment1 myFragment1 = new MyFragment1();
MyFragment2 myFragment2 = new MyFragment2();
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_life_cycle2);
Log.i(TAG, "onCreate");
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.container_fragment1, myFragment1);
ft.add(R.id.container_fragment2, myFragment2);
ft.commit();
}
....
}这里只摘了重要代码片段,打印出的Log如下:
LifeCycle2Activity: onCreate MyFragment1: onAttach(Activity) MyFragment1: onAttach(Context) MyFragment1: onCreate MyFragment2: onAttach(Activity) MyFragment2: onAttach(Context) MyFragment2: onCreate MyFragment1: onCreateView MyFragment1: onActivityCreated MyFragment2: onCreateView MyFragment2: onActivityCreated LifeCycle2Activity: onStart LifeCycle2Activity: onResume
从中可以看出,不同
Fragment
的创建是依次进行的,但它们都遵循上面那张图的规则。Fragment
之间的替换1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public class LifeCycle2Activity extends FragmentActivity {
private final String TAG = getClass().getName();
MyFragment1 myFragment1 = new MyFragment1();
MyFragment2 myFragment2 = new MyFragment2();
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_life_cycle2);
Log.i(TAG, "onCreate");
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.container_fragment1, myFragment1);
ft.commit();
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getSupportFragmentManager().beginTransaction().
replace(R.id.container_fragment1, myFragment2)
.addToBackStack(null)
.commit();
}
});
}
.....
}上面的例子中,
Activity
先加载MyFragment1,然后在点击按钮时,用MyFragment2替换MyFragment1。打印出的Log如下:MyFragment2: onAttach(Activity) MyFragment2: onAttach(Context) MyFragment2: onCreate MyFragment1: onDestroyView MyFragment2: onCreateView MyFragment2: onActivityCreated
可以发现,原来的
Fragment
的视图会被销毁,新的Fragment
则会重建。但上面的生命周期流程图显示,只有在Activity
进入Destroy
状态时,Fragment
才会执行onDestroyView()
动作,Log里面MyFragment1
却执行了onDestroyView()
方法,有点费解。如果
Activity
中包含较多的Fragment
,比较好的方式是将它们缓存起来,防止频繁地创建和回收资源造成内存“抖动”现象。Google之所以提倡使用Fragment
,是因为Fragment
占用的资源比Activity
小,这样,如果可以把视图都嵌入到多个Fragment
中,而共用同一个Activity
,可以更加合理地使用内存和CPU资源。
<br>
Activity
与View
生命周期比较
笔者之前比较关注自定义View
的一些知识,但比较忽略View
生命周期相关的东西,直到前不久的项目中需要获得View
的宽高后才遇到了问题,所以这一块有必要总结一下。
我简单地自定义了一个View
,并在一些关键的回调函数里面打了Log:
1 | public class MyView extends View { |
将这个View
放到Activity
的Layout文件中,启动Activity
时会打出如下Log:
MyView: call Constructor LifeCycle1Activity: onCreate LifeCycle1Activity: onStart LifeCycle1Activity: onResume MyView: call onMeasure MyView: call onMeasure MyView: call onMeasure MyView: call onMeasure MyView: call onLayout MyView: call onMeasure MyView: call onMeasure MyView: call onLayout MyView: call onDraw
结果明确地告诉我们,View
只有在Activity
执行完onResume()
动作后才会开始测量绘制工作,在这之前它仅仅是实例化了自己。相信很多人刚开始接触Android时,都曾经尝试过在onCreate()
函数里去获取View
的宽高,结果总是得到0。现在看来那是再自然不过的事情了,因为View
只有测量绘制后才会有宽高。
另外,View
只会测量并布局一次,之后如果Activity
从后台重新返回前台,View
只会执行onDraw()
方法,下面是Activity
切换回来后打印的Log:
LifeCycle1Activity: onStop LifeCycle2Activity: onPause LifeCycle1Activity: onRestart LifeCycle1Activity: onStart LifeCycle1Activity: onResume MyView: call onDraw LifeCycle2Activity: onStop
显然,Activity
执行onResume()
后界面需要重绘,所以需要执行onDraw()
函数,但View
的宽高及摆放位置是一样的,所以onMeasure()
、onLayout()
便不必再执行。
现在问题来了,如果onResume()之后才开始测量绘制,我们要如何得到View的宽高呢?Google为每一个View提供了一个ViewTreeObserver类来帮我们监听View的一些动作,可以通过注册OnGlobalLayoutListener监听器来获得View的宽高等信息,见下面的代码:
1 |
|
在onCreate
函数中,我在myView
上注册了OnGlobalLayoutListener
监听器,结果打印的Log如下:
MyView: call Constructor LifeCycle1Activity: onCreate LifeCycle1Activity: onCreate width===>0 height===>0 LifeCycle1Activity: onStart LifeCycle1Activity: onResume MyView: call onMeasure MyView: call onMeasure MyView: call onMeasure MyView: call onMeasure MyView: call onLayout LifeCycle1Activity: onGlobalLayout width===>350 height===>350 MyView: call onMeasure MyView: call onMeasure MyView: call onLayout MyView: call onDraw
不难看出,这个监听器会在测量得到宽高后被调用,并返回正确的宽高。关于View
生命周期更多的东西,可以参考后面提供的链接。
<br>