Android四大组件之Activity

 生命周期

 

 1. Activity的entire lifetime全部的生命期)发生在调用onCreate()和调用onDestory()之间。

   在onCreate()方法中执行全局状态的建立(例如定义布局),在onDestroy()方法中释放所有保存的资源。

 2.Activity的visible lifetime(可见的生命期)发生在调用onStart()onStop()之间。

   在这个期间,用户能在屏幕上看见Activity,和它进行交互。系统在Activity的完整寿命中可能多次调用onStart()onStop(),正如Activity交替地对用户可见或隐藏。

 3.Activity的foreground lifetime (前台的生命期)发生在调用onResume()onPause()之间。

   在这期间,Activity在屏幕上所有其他Activity的前面,有用户输入焦点。

 一个Activity能频繁的在前台进入和出去之间转变

 总结:

 onCreate: 在这里创建界面,做一些数据的初始化的工作.

 onStart: 到这一步变成用户可见不可交互的.

 onResume:变成和用户可交互的

 onPause:到这一步是可见不可交互的,系统会停止动画等消耗CPU的事情,应该在这里保存(onSaveInstanceState)你的一些数据,因为这个时候你的程序        的优先级降低,有可能被系统回收。在这里保存的数据,应该在onResume里读出来。(注意:这个方法里做的事情时间要短,因为下一个activity        不会等这个方法完成才启动)

 onStop: 变得不可见,被下一个activity覆盖了(onPause 和 onStop的区别为是否可见)

 onDestroy: 这是activity 被干掉之前最后一个被调用的方法了。

这里提一下onPause和onStop的区别: onPause是在整个窗口被半遮盖或者半透明的时候会执行,而onStop则是在整个窗口被完全遮盖才会触发, 触发onStop的方法之前必定会触发onPause方法。

1.运行应用,MainActivity运行。

可以看出一个Activity运行调用的回调方法是:  onCreate()->onStart()->onResume()


2. 点击跳转按钮,由MainActivity跳转到SecondActivity:

     1>SecondActivity是Dialog。


由于SecondActivity是Dialog,所以MainActivity依然可见,所以只调用了它的onPause()方法。

     2>若将SecondActivity改为不是Dialog

(只需在Manifest.xml文件中删掉 android:theme="@android:style/Theme.Dialog"这一行即可)

  再点击跳转按钮:


   对于MainActivity,由于不可见,状态由运行变为停止。依次调用了它的回调方法: onPause()->onStop()

3.Activity处于运行状态时,点击返回按钮:

点击返回按钮,Activity由运行状态变为死亡状态,依次调用它的回调方法:  onPause()->onStop()->onDestroy()

4.Activity处于运行状态,点击主页按钮,返回桌面:


   Activity由运行状态变为停止状态,依次调用它的回调方法:  onPause()->onStop()

5.Activity处于停止状态,即由桌面返回到Activity   


 停止->运行,依次调用回调方法:onRestart()->onStart()->onResume()

6.Activity处于运行状态,旋转屏幕:


     可以看出,旋转屏幕是一个销毁Activity然后重新创建Activity的过程。

     运行->暂停->停止->死亡->运行

  依次调用回调方法:onPause()->onStop->onDestroy()->onCreate()->onStart()->onResume()


关于横竖屏切换 参考http://android.tgbus.com/Android/tutorial/201103/346550.shtml

我们可以为一个Activity指定一个特定的方向,指定之后即使转动屏幕方向,显示方向也不会跟着改变:

  (1).指定为竖屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="portrait",或者在onCreate方法中指定:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  //竖屏 

  (2).指定为横屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="landscape",或者在onCreate方法中指定:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //横屏 

设置Activity的android:screenOrientation="portrait"属性时,无法切换横竖屏,因此不但不会重新调用各个生命周期方法,而且onConfigurationChanged()方法也不会执行。

7.Activity处于运行状态,手机此时锁屏

    

 可以看出,手机锁屏,此时由于Activity不可见,会进入停止状态。

    依次调用回调方法:onPause()->onStop()

8.当应用正在运行时,手机锁屏,然后解锁回到应用界面 

     

  可以看出应用从停止状态恢复到运行状态。

     依次调用回调方法:onRestart()->onStart()->onResume()  


总结一下整个Activity的生命周期

补充一点,当前Activity产生事件弹出Toast和AlertDialog的时候Activity的生命周期不会有改变

Activity运行时按下HOME键(跟被完全覆盖是一样的):onSaveInstanceState à  onPause  à  onStop à  onRestart  à   onStart à   onResume

Activity未被完全覆盖只是失去焦点:onPause--->onResume

Android 系统的开机启动过程

参考: 

1.Android系统的开机启动过程

2.http://gold.xitu.io/entry/57382e1f2e958a0069cc8eae


  当linux内核启动后会初始化各种软硬件环境,加载驱动程序,挂载根文件系统,并开始执行根文件系统的init程序,init程序是Android启动过程中最重要的核心程序。

init进程是Android系统中用户进程的鼻祖进程。init进程会启动各种系统本地服务,如:Media Server、Service Manager、bootanim(开机动画)等。init进程会在解析init.rc文件后fork出Zygote,而Zygote是所有Java进程的父进程,我们的App都是由Zygote fork出来的。

  Zygote进程主要包含:

   加载ZygoteInit类,注册Zygote Socket服务端套接字;

   加载虚拟机;

   预加载Android核心类

   预加载系统资源

  随后Zygote进程会fork出System Server进程,System Server进程负责启动和管理整个framework,包括Activity Manager,PowerManager等服务。

  当System Server将系统服务启动就绪后,就会通知ActivityManager启动首个Android程序Home即我们看到的桌面程序。


Android系统启动过程,app启动过程:

参考:http://www.jianshu.com/p/6037f6fda285#


在安卓系统上,应用在没有进程的情况下,应用的启动都是这样一个流程:当点击app的启动图标时,安卓系统会从Zygoteˈzaɪgəʊt]进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类、创建MainActivity类、加载主题样式Theme中的windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上,所以直到这里,应用的第一次启动才算完成,这时候我们看到的界面也就是所说的第一帧。

所以,总结一下,应用的启动流程如下:

Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量布局绘制显示在界面上。

Activity 启动模式:

(1)AndroidMainifest文件中设计的四种启动模式:

standard:

   默认的启动模式,如果不指定Activity的启动模式,则使用这种方式启动。这种启动模式每次都会创建新的实例,每次点击standard模式创建Activity后,都会创建新的MainActivity覆盖在原Activity上。

singleTop

   如果指定启动的Activity为singleTop模式,那么在启动的时候,系统会判断当前栈顶Activity是不是要启动的Activity,如果是则不创建新的Activity而直接引用这个Activity;如果不是则创建新的Activity。这种启动模式通常适用于收到消息后显示的界面,例如QQ接受到消息后弹出Activity,如果一次来10次消息,总不能一次弹10个Activity,点进去应该都是同一个Activity。

singleTask

   singleTask模式与singleTop模式类似,只不过 singleTop模式是检测栈顶元素是否需要启动的Activity,而singleTask是检测真个Activity栈中是否存在需要启动的Activity。如果存在,则将Activity置于栈顶,并将该Activity以上的Activity都销毁、不过这里是指同一个app中启动这个singleTask的Activity,如果其他程序以singleTask模式来启动这个Activity,那么它创建一个新的任务栈。这里还有一点需要注意的是,如果启动的模式为singleTask的Activity已经在后台的一个任务栈中了,那么启动后,后台的这个任务栈将一起被切换到前台。

singleInstance

   不同于以上三种启动模式,指定为 singleInstance模式的活动会启用一个新的返回栈来管理这个活动(其实如果 singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。那么这样做有什么意义呢?想象以下场景,假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?使用前面三种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用 singleInstance模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。(具体实例见第一行代码p75).

   singleInstance这种启动模式和使用的浏览器的工作原理类似。在多个程序中访问浏览器时,如果当前的浏览器没有打开,则打开浏览器,否则会在当前打开的浏览器中继续访问。申明为singleInstance的Activity会出现在一个新的任务栈中,而且该任务栈中值存在这一个Activity。举个例子来说,如果应用A的任务栈中创建了MainActivity实例,而且启动模式为singleInstance,如果应用B也要激活MainActivity,则不需要创建,两个应用共享该Activity实例。

(2)Intent Flag启动模式

  (1)Intent.FLAG_ACTIVITY_NEW_TASK使用一个新的task来启动Activity,一般用在service中启动Activity的场景,因为service中并不存在Activity栈。

  (2)Intent.FLAG_ACTIVITY_SINGLE_TOP类似andoid:launchMode="singleTop"

  (3)Intent.FLAG_ACTIVITY_CLEAR_TOP:类似andoid:launchMode="singleTask"
  (4)Intent.FLAG_ACTIVITY_NO_HISTORY使用这种模式启动Activity,当该Activity启动其他Activity后,该Activity就消失了,不会保留在task栈中。例如A B,在B中以这种模式启动C,C再启动D,则当前的task栈变成A B D。
  (1)clearTaskOnLaunch:每次返回该Activity时,都将该Activity之上的所有Activity都清除。通过这个属性可以让task每次在初始化的时候都只有这一个Activity。
  (2)finishOnTaskLaunch:clearTaskOnLaunch作用在别的Activity身上,而finishOnTaskLaunch作用在自己身上。通过这个属性,当离开这个Activity所在的task,那么当用户再返回时,该Activity就会被finish掉。
  (3)alwaysRetainTaskState如果将Activity的这个属性设置为true,那么该Activity所在的task将不接受任何清理命令,一直保持当前task状态,相当于给了task一道”免死金牌”。

(3)清空任务栈

任务和返回栈(tasks and back stack)

    一个Task 就是一组activity的集合。这些activity按照它们打开的顺序被放置于一个先进后出的栈中(back stack)。

   用户点击图标打开一个app时,该app的task会被移到前台显示。如果当前没有该app的task,系统将会新建一个task并在其中运行Main activity。

   一个activity(A)打开另一个activity(B),B将会被置于栈顶并显示,A仍然处于栈中,系统会保存它的状态。如果按下返回键,当前的activity将被弹出并destroy掉,前一个activity被resume并重新显示(还原stop前的UI显示)。

   下图表示2个activity切换过程该栈的状态。


用户可以通过返回键令task返回栈中的activity依次弹出,当最后一个activity也被弹出后,该task便不再存在。

如果HOME键被按下,从当前app回到桌面,该appTask会被移到后台,后台的task所属的所有activity都是stop状态,且back stack依然存在——这个task其实只是失去了和用户交互的焦点。

多个task可以同时存在后台,但是系统也会停止一些activity来释放空间,导致activity的状态丢失。


   Back stack中的activity不会被重新排位,如果同一个activity能被其他多个activity 启动,这个activity都会创建新实例推入栈中:


 总结Activity和task的默认行为:

• Activity A启动了Activity B,A会被stop,但状态仍然保存(UI,如活动条的位置,EditText输入的文字),从B返回,A被resumed并恢复之前的状态。

• 点击HOME返回桌面,当前的task被移到后台,系统会保存task中每一个activity的状态;直到用户点击app图标返回,该task被移回前台,resume栈顶的activity 。

• 返回键会导致当前的activity从栈顶弹出并被destroy,该activity状态不会再被保存,前一个activity移到栈顶。

• Activity能被实例化多次,包括其它task启动它。

onWindowFocusChanged

   onWindowFocusChanged方法:在Activity窗口获得或失去焦点时被调用,例如创建时首次呈现在用户面前;当前Activity被其他Activity覆盖;当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;用户退出当前Activity。以上几种情况都会调用onWindowFocusChanged,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用,如图所示:


   这个方法在某种场合下还是很有用的,例如程序启动时想要获取视特定视图组件的尺寸大小,在onCreate中可能无法取到,因为窗口Window对象还没创建完成,这个时候我们就需要在onWindowFocusChanged里获取;如果大家已经看过我写的Android动画之Frame Animation这篇文章就会知道,当时试图在onCreate里加载frame动画失败的原因就是因为窗口Window对象没有初始化完成,所以最后我将加载动画的代码放到了onWindowFocusChanged中,问题迎刃而解。不过大家也许会有疑惑,为什么我在代码里将它注释掉了,因为对当前Activity每一个操作都有它的执行log,我担心这会影响到整个流程的清晰度,所以将它注掉,大家只要了解它应用的场合和执行的顺序就可以了。

onSaveInstanceState与onRestoreInstanceState

   Activity里的onSaveInstanceState()方法,虽然系统会自动调用它来保存Activity的一些数据,但当除它默认要保存的数据外,我们还要保存一些其他数据的时候,我们就需要覆盖onSaveInstanceState()方法来保存Activity的附件信息。例如在播放视频过程中,横竖屏切换要保持当前播放时间进度,在默认情况下播放时间是不被自动保存的。

   onSaveInstanceState与onRestoreInstanceState的作用:

在资源紧张的情况下,系统会选择杀死一些处于非栈顶的Activity来回收资源。为了能够让这些可能被杀死的Activity能够在恢复显示的时候状态不丢失,所以需要在Activity从栈顶往下压的时候提供onSaveInstanceState的回调用来提前保存状态信息。

而onRestoreInstanceState则是在这个Activity真的回收掉之后的恢复显示阶段用来恢复之前保存的数据。

   onSaveInstanceState与onRestoreInstanceState的调用时机:

只要某个Activity是做入栈并且非栈顶时(启动跳转其他Activity或者点击Home按钮),此Activity是需要调用onSaveInstanceState的, 如果Activity是做出栈的动作(点击back或者执行finish),是不会调用onSaveInstanceState的。

只有在Activity真的被系统非正常杀死过,恢复显示Activity的时候,就会调用onRestoreInstanceState。

   onSaveInstanceState方法会在什么时候被执行,有这么几种情况:

   1、当用户按下HOME键时。

  这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机 会保存某些非永久性的数据。以下几种情况的分析都遵循该原则

   2、长按HOME键,选择运行其他的程序时。

   3、按下电源按键(关闭屏幕显示)时。

   4、从activity A中启动一个新的activity时。

   5、屏幕方向切换时,例如从竖屏切换到横屏时。

   在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行

   总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。

 

    onRestoreInstanceState:需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行

  另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值