当用户在用一个App的时候,Activity会在生命周期不同的状态下转换。
当用户离开或重新回到一个Activity,我们可以在生命周期的回调函数中来写一些相关的操作。比如,如果用户打开了一个视频播放器,当他直接切换到另外一个App,这时候应该使播放器暂停,断开获取视频资源的网络连接。当用户回来,我们要重新连接网络获取视频资源,让用户在刚才暂停的位置开始重新观看。
接下来,开始去了解非常重要的生命周期的回调函数,学着怎么去用它们来执行一些使用户有更好体验的操作,并且当我们不需要它们时,不要消耗系统的资源。在Android系统中,不是跟其他程序一样会启动一个main()方法, 而是通过调用对应生命周期特定状态的回调函数,来开始一个Activity实例.
在一个Activity的生命周期中,其中的回调函数可以看成一个阶梯金字塔。也就是,每一个Activity生命周期的阶段就是金字塔上的一个台阶。当系统开始启动一个Activity时,其中的回调函数会让Activity一个台阶一个台阶地登上最高的那一台阶。在最高的那一层台阶,运行时Activity可以完全显示出来,和用户进行交互。
当用户退出当前的Activity,系统会调用其它的方法,让Activity从最高那层台阶往下走,它就不会在前台了。有些时候,它只是从金字塔往下走了一部分,然后在那等着(比如说用户切换到其它的App)。这个时候这个Activity还是可以往上走回到金字塔最高那一层(用户又回到了之前的Activity),用户继续在刚才离开的地方进行操作。
可能实际开发上不需要实现所有的生命周期函数,但是了解每一个函数的实现,确保App执行的是用户期望的方式,这是非常重要的。
以下是要注意的几个方面:
1、当用户有来电或者切换到其它的App,不要销毁当前的App
2、当用户没有用到系统的资源,要关掉,不要消耗系统资源
3、当用户离开App一会后再到App,不要丢失用户的进度
4、当屏幕在横向和纵向之间旋转时,不要失去用户的进度。
Activity在不同的阶段转换时,如上图。
但是,只有三个阶段是静态的。Activity只会在这三个阶段其中一个阶段上长时间停留:
Resumed
在这一阶段,Activity会显示在前台上,和用户进行交互。也就是运行的阶段。
Paused
在这个阶段,Activity会被其他的Activity部分地遮盖住,这时候的Activity不能接收用户的输入也不能执行任何代码。
Stopped
当Activity在Stopped阶段,会完全被掩盖住,用户不可见。这是的Activity实例和他的一些成员变量仍然保留,但它不会执行任何代码了。
而在其他的阶段 (Created 和 Started) 都是一瞬间的, 系统会调用下一个生命周期的函数,很快地跳到下一个阶段。所以在系统调用 onCreate()之后,它很快就会调用onStart()接着马上跟着 onResume()。
指定App的启动Activity
在AndroidManifest.xml中,可以指定哪一个Activity用作main Activity。这个main Activity要在< intent-filter >中声明,包含MAIN action 和 LAUNCHER category.
例如:
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
大部分的App都会有几个不同的Activity,当用户点击打开App时,系统会通过调用onCreate()方法来创建每个新的Activity。
必须要实现 onCreate()方法来执行一些活动的UI、数据等加载,这在整个生命周期只执行一次。例如在XML中定义用户界面口,定义成员变量,配置一些UI。
上一次DisplayActivity中的代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.content);
layout.addView(textView);
}
一旦 onCreate()执行完成, 系统就会紧接着调用 onStart() 和 onResume() 方法. Activity不会停留在Created和Started这两个阶段。其实,当onStart()方法被调用的时候,用户已经可以看见Activity,只不过onResume()会马上被调用,Activity就进入在Resumed这一状态,直到用户切换到另一个App或者有来电了,又或者关闭了屏幕。
当创建一个新的Activity实例时,重点关注这三个回调方法 :onCreate(), onStart(), 和 onResume()。一旦回调方法执行完成,Activity就会到Resumed这一阶段,即Activity回到前台,用户就可以和这个Activity进行交互。
onCreate()在生命周期中是第一个执行的方法,而onDestroy()是生命周期中最后一个执行的方法. 系统在Activity中调用onDestroy()这个方法作为结束的信号,Activity实例会从系统内存中移除。
大部分App都不需要实现这个方法,因为Activity调用onDestroy()前,应该在onPause() 和onStop()这两个方法中执行清除内存操作。但是如果Activity中有线程是在onCreate()中或者一些长期运行的资源,如果不合适地关掉的话,会造成内存泄漏!这是时候应该在最后的onDestroy()方法中关掉它们。
@Override
public void onDestroy() {
super.onDestroy();
}
系统在调用onPause()和onStop()方法之后,就会调用onDestroy()用。
除了一种情况:就是在onCreate()中调用finish()方法。
有时候,比如Activity执行一个临时的决策来启动另一Activity,就会在onCreate()中调用finish()方法。这种情况,系统会马上调用onDestroy()方法,不会再经过生命周期的其他回调方法。
在用户使用app时,前台Activity有时被其他组件遮住,会导致Activity暂停。例如,当一个提示对话框打开,Activity就会暂停。虽然仍可以看见部分的Activity,但是Activity已经暂停,不会执行任何操作。如果Activity一旦完全被遮盖着看不见,它就停止了。会进入Stopped这一状态。
当Activity进入Paused状态,系统会在Activity中调用onPause(),比如会暂停视频,或者暂时保存 一些信息。当用户从Paused状态返回到当前的Activity,系统就会调用onResume()方法,重新回到Resumed状态。
当系统调用onPause(),Activity部分可见。但大多数的情况是,用户会离开当前的Activity,就会进入Stopped状态,最后执行onDestroy()方法。所以呢,在onPause()中会做一下几点:
1、停止会消耗CPU的动画或者正在运行的操作。
2、提交未保存的修改,比如草稿邮件/3、释放系统资源,比如广播接收器,GPS,或者当Activity暂停,而用户又不需要用到的资源
例如,App用到相机,那么onPause()方法是一个非常合适的地方来释放它
@Override
public void onPause() {
super.onPause(); //首先调用父类的方法
// 释放资源,因为其他的Activity可能需要用到它
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
注意,不要在onPause()方法中执行数据库的操作,因为这会使跳转到下一个Activity很缓慢。
在onPause()执行一些相对简单的操作,以致于可以快速地跳转到下一个Activity。当Activity停止,这时候Activity实例会放在内存中,当Activity恢复时,就会重新调用这个实例,不需要再重新创建一个Activity实例。
需要知道的是,每一次系统调用onResume()方法,Activity就会回到前台,其中也包括了第一次创建实例的时候。
应该在onResume()方法中初始化一些在onPause()被释放掉的组件,还有每次恢复所需要的组件,比如一些开始的动画和需要的组件。
以下onResume()对应上面onPause()的例子,初始化在Pasued状态被释放掉的相机。
@Override
public void onResume() {
super.onResume();
if (mCamera == null) {
initializeCamera(); // 初始化相机的操作
}
}