生命周期
- onCreate( ): 表示Activity正在被创建,这是生命周期的第一个方法,可以做一些初始化的工作。
- onRestart( ): 表示Activity正在重新启动,Activity从不可见变为可见状态时,会被调用,比如点击Home键又回到这个Activity时,就会调用onRestart( )。
- onStart( ): 表示Activity正在被启动,即将开始,这时Activity已经可见了,但还没出现在前台,无法跟用户交互。
- onResume( ): 表示Activity已经可见了,并且出现在前台并开始活动了。
- onPause( ) : 表示Activity正在停止,正常情况下,onStop紧接着被调用,此时可以做一些存储数据、状态存储等轻量级的存储工作,在一些情况下,onPause方法或许是活动触发的最后的方法,因此开发者需要在这个时候保存需要保存的信息。
- onStop( ) : 表示Activity即将停止,如果内存紧张,系统会直接结束这个活动,而不会触发 onStop 方法。 所以保存状态信息是应该在onPause时做,而不是onStop时做。
- onDestroy :当Activity销毁的时候,触发该方法。和 onStop 方法一样,如果内存紧张,系统会直接结束这个Activity而不会触发该方法。我们可以在这里做一些回收工作和最终的资源释放。
- onSaveInstanceState ():系统调用该方法,允许Activity保存之前的状态,比如说在一串字符串中的光标所处的位置等。 通常情况下,开发者不需要重写覆盖该方法,在默认的实现中,已经提供了自动保存活动所涉及到的用户界面组件的所有状态信息。
几种常见情况的生命周期调用流程:
1.针对一个特定的Activity,第一次启动,回调是 onCreate -> onStart -> onResume.
2.当打开新的Activity或者切换到桌面时: onPause -> onStop。
有一个特殊情况是当新Activity是透明主题时,那么当前Activity不会回调onStop。
3.当用户回到原Activity,且原Activity未被销毁时: onRestart -. onStart -> onResume .
4.当用户按下back键时: onPause -> onStop -> onDestroy.
Activity之间的协调
当一个activity启动另一个时,两者都在走生命周期。如果这两个activity之间要共享数据,那么重点要理解当第二个activity被创建时,第一个activity还没有执行到onStop()。开始新一个和结束前一个之间有交集。
当activityA启动ActivityB时,会按以下顺序执行:
1Activity A 的onPause()执行。
2Activity B的onCreate(),onStart(),onResume()依次执行(此时actvityB具有用户焦点)。
3Activity A的onStop()被执行(假设A被B完全遮盖)。
你应跟据这个顺序来管理两者之间的数据传递。比如,如果A要向数据库中写入数据,要保证B在初始化时能读到A写入的完整数据,那么A应在onPause()方法中写入数据,而不能在onStop()中写入。
四种启动方式
任务栈的概念:
1.程序打开时就创建了一个任务栈, 用于存储当前程序的activity,所有的activity属于一个任务栈。
2.一个任务栈包含了一个activity的集合, 去有序的选择哪一个activity和用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
3.任务栈可以移动到后台, 并且保留了每一个activity的状态. 并且有序的给用户列出它们的任务, 而且还不丢失它们状态信息。
4.退出应用程序时:当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。
任务栈的缺点:
1.每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
2.每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。
因此,我们引入了启动模式来修改系统的默认行为:
<activity android:name=".MainActivity" android:launchMode="standard" />
其中的launchMode有四种方式:
1.singleTask:标准模式,每次启动一个Activity 都会重新创建一个新的实例,不管这个实例是否已经存在。
2.singleTop: 栈顶复用模式,如果新Activity 已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数,我们可以取出当前请求的信息。
3.singleTask: 栈内复用模式,只要Activity在一个栈中存在,那么多次启动都不会重新创建实例,当需要运行的Activity不在栈顶时,系统会清空目标Activity上面的其他Activity(clearTop),使目标Activity实例成为栈顶。
**4.singleInstance **:单实例模式,在这种加载模式下,系统保证只会创建一个目标Activity实例,并会使用一个全新的Task栈来加载该Activity实例。采用singleInstance模式加载的activity所在的Task只包含该Activity.
使用场景
singleTop适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
singleTask适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。之前打开过的页面,打开之前的页面就ok,不再新建。
singleInstance适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。
另外,stackflow的一位大神也总结得很好:
Between the Browser and Alarm Clock applications, you cover all four launch modes:
1.BrowserActivity uses singleTask. There is only one browser activity at a time and it doesn't become part tasks that send it intents to open web pages. While it might return to whatever most recently launched it when you hit back it is actually fixed at the bottom of its own task activity stack. It will share its task with activities that it launches like bookmarks.
2.BrowserBookmarksPage uses singleTop. While there can be multiple instances of this activity, if there is already one at the top of the task's activity stack it will be reused and onNewIntent() will be called. This way you only have to hit back once to return to the browser if the bookmarks activity is started multiple times.
3.AlarmClock uses standard. The user can launch multiple instances of this activity and these instances can be part of any task and anywhere in the activity stack. As a fairly simple application it doesn't really demand tight control of its activity.
4.AlarmAlert uses singleInstance. Only one alert activity at a time and it is always its own task. Anything it launches (if anything) becomes part of its own new task.
启动一个Activity
你可以用startActivity()启动一个activity,它有一个参数是intent,你需要在这个intent中指明要调用的activity。Intent中你可以明确地指定要启动的activity,或只指定activity的类型,此时系统会为你挑选一个合适的activity,这个activity可能位于其它程序中,也可能位于你自己的程序中。Intent的putextra方法中可以带一些被新activity使用的数据(相当于参数传递)。然后在新Activity中调用getIntent方法获取Intent实例,并得到里面的数据。
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
** Activity的关闭**:Activity可以内部调用finish()方法关闭它自己,也可以调用finishActivity()方法关闭其它的activity。