Android知识点<1> Activity 相关知识

1. Activity 的生命周期

1.1 七个周期函数:
onCreate(), onStart(), onRestart(), onResume(), onPause(),onStop(), onDestroy()。
onCreate(): 创建Activity时调用,设置在该方法中,还以Bundle的形式提供对以前存储的任何状态的访问。
onStart(): Activity变为在屏幕上对用户可见时调用。
onResume(): Activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法总是被调用。
onPause(): Activity被暂停或收回cpu和其他资源时调用,该方法用户保护活动状态的,也是保护现场。
onStop(): Activity被停止并转为不可见阶段及后续的生命周期事件时调用。
onRestart(): Activity被重新启动时调用。该活动仍然在栈中,而不是启动新的Activity。

具体周期的操作 :
onCreate函数:注册你要用到的变量,比如说service,receiver,这些变量是无论你的Activity是在前台还是在后台都能够被响应到的,调用setContentView()函数初始化布局信息。
onStart函数:注册一些变量。这些变量必须在Android Activity类在前台的时候才能够被响应(或者这样说更明确,变量的注册更应当放在onCreate中,但是有些变量的注册必须在activity处于前台时才可行,这些则放在onStart中)。
onResume函数:调用一些刷新UI的函数,每当Activity调用到这里时就要刷新一下UI各控件的状态。 
onPause函数:一般是做一些变量的设置,或者保存,因为这个时候Activity马上就要切到后台处理,可能有些变量就要被释放掉或者状态要做些相应的调整。
onStop函数:反注册在onStart函数中注册的变量。
onDestory函数:反注册在onCreate中注册的变量

典型的几个问题解析:

1. Home键和Back键的区别

home键 :onpause->onstop->onrestart->onstart->onresume (如果activity采用透明主题,那么不会调用onstop)

back键 :onpause->onstop->ondestory->oncreate->....

2. activityA 调用 activity B ,Activity 的onpause先执行,然后B 的 oncreate 才会执行。所以不能在onpause里边做重量操作

3. alertdialog 不会影响Activity的生命周期,也就是说,dialog显示的时候,onpause不会执行

4. 横竖屏切换时候Activity的生命周期。

    1、不设置Activity的android: configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。
    2、设置Activity的android: configChanges=“orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次。
    3、设置Activity的android: configChanges=“orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfiguration方法
5. savaInstanceState何时执行:
    1.当用户按下HOME键时。
    2.打开任务列表(长按HOME键/长按选项键,因机型而异),按下就执行保存数据。
    3.从甲Activity 中启动一个新的activity时
    4.屏幕横竖屏切换
    5、锁屏(锁屏会执行savaInstanceState,解锁不会执行)(参见 一、3.6)
6. onRestoreInstanceState何时执行
    Activity被异常销毁后打开Activity,
    横竖屏切换后打开Activity,
    或者说gc回收后打开Activity

7. Activity 跳转过程中调用的方法

一般情况下比如说有两个activity,分别叫A,B。

当在A 里面激活B 组件的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。

这个时候B覆盖了A的窗体, A会调用onStop()方法。

如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。

如果B已经存在于Activity栈中,B就不会调用onCreate()方法。


1.2 Activity的四种状态
    Running状态:新的Activity启动入栈后,屏幕最前端,栈的最顶端,处于可见和用户交互的激活状态。
    Paused状态:当Activity被另一个透明或者Dialog样式的Activity覆盖时的状态。仍可见,但是失去焦点
    Stopped状态:当Activity不可见时,Activity处于Stopped状态。当Activity处于此状态时,一定要保存当前数据和当前的UI状态,否则一旦
                        Activity退出或关闭时,当前的数据和UI状态就丢失了。
    Killed状态:Activity被杀掉以后或者被启动以前,处于Killed状态。这是Activity已从Activity堆栈中移除,需要重新启动才可以显示和使用。
    4种状态中,Running状态和Paused状态是可见的,Stopped状态和Killed状态时不可见的。

1.3 Activity的启动方式

** standard 默认的启动模式,标准模式**
每开启一个Activity,就会在栈顶添加一个Activity实例。多次间隔或者直接启动一个甲Activity会添加多个甲的示例,可重复添加。(间隔 ABA, 直接 ACC或者AAA)
Service和ApplicationContext是没办法直接开启一个新的Activity,因为只有Activity类型的Context的Activity才能开启,但还是有解决办法的,那就是让我们要开的那个新的Activity设置为FLAG_ACTIVITY_NEW_TASK标识。
** singletop 单一顶部模式 (顶部重复)**
如果开启的Activity已经存在一个实例在任务栈的顶部(仅限于顶部),再去开启这个Activity,任务栈不会创建新的Activity的实例了,而是复用已经存在的这个Activity,onNewIntent方法被调用;之前打开过,但不是位于栈顶,那么还是会产生新的实例入栈,不会回调onNewIntent方法。
Intent.FLAG_ACTIVITY_SINGLE_TOP
应用场景:
适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。从外界可能多次跳转到一个界面
** singleTask 单一任务栈,干掉头上的其他Activity**
结论:如果开启的甲Activity已经存在一个实例在任务栈S1,再去开启这个Activity,位于栈顶则直接复用,回调onNewIntent方法;位于里面,也是复用,回调onNewIntent方法,复用的同时的是直接把自己上方的全部Activity都干掉。
Intent.FLAG_ACTIVITY_CLEAR_TOP
在一个打开时已经被标记为FLAG_ACTIVITY_CLEAR_TOP的界面(现正处于前台任务栈的栈顶),如果我们在此界面打开自己,并且一样标记为FLAG_ACTIVITY_CLEAR_TOP,那么这个时候会经历一次建新毁旧的过程,任务栈里面从结果的来说没什么变化,但是生命周期的着眼于过程的角度来却经历非常大的变化。(下面的情况5有示例)
适合作为程序入口点。
例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。之前打开过的页面,打开之前的页面就ok,不再新建
** singleInstance 单一实例(单例),任务栈里面自已自己一个人**
结论:当启动一个启动模式为singleInstance的Activity时(之前没启动过),这时系统将开辟出另外一个任务栈,用于存放这个Activity,而且这个新的任务栈只能存放自身这唯一一个Activity。singleInstance页面作为前台任务打开自己打开自己,则复用,任务栈顺序无变化;singleInstance页面作为后台任务栈,则切换成为前台任务栈,无新实例产生,复用。
复用就会调用onNewIntent方法。
电话,闹钟.
适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,再次启动,首先打开的是B。某个应用中用到了google地图,当退出该应用的时候,进入google地图,还是刚才的界面


taskAffinity介绍
通常一个应用中所有的Activity有相同的affinity,即拥有相同taskAffinity值的Activity值属于同一个Task。 不同应用程序中的Activity可以拥有相同的Affinity,同一个应用程序中不同Activity 也可以设置成不同的Affinity。 taskAffinity的使用会拥有下面两种情况:
1)当传递给StartActivity()的Intent对象包含 FLAG_ACTIVITY_NEW_TASK标记时,系统会为需要启动的Activity寻找与当前Activity不同Task。 如果要启动的 Activity的Affinity属性与当前所有的Task的Affinity属性都不相同,系统会新建一个带那个Affinity属性的Task,并将要启动的Activity压到新建的Task栈中,否则将Activity压入那个Affinity属性相同的栈中
2)allowTaskReparenting属性设置为true 如果一个activity的allowTaskReparenting属性为true, 那么它可以从一个Task移到另外一个有相同Affinity的Task中,更换从属的Task。 如果一个.apk文件从用户角度来看包含了多个”应用程序”,你可能需要对那些 Activity赋不同的Affinity值


栈的管理
当应用长时间置于后台,系统可能会清理应用Task栈中的Activity,当用户返回应用保留的只有应用的启动Activity。 通过以下设置改变这种行为!
  • alwaysRetainTaskState: 如果栈底Activity的这个属性被设置为true,Task中的所有activity将被长时间保存
  • clearTaskOnLaunch:如果栈底activity的这个属性被设置为true,一旦用户离开Task, 则 Task栈中的Activity将被清空到只剩下栈底activity。 这种情况刚好与 alwaysRetainTaskState相反。 即使用户只是短暂地离开,task也会返回到初始状态 (只剩下栈底acitivty)
  • finishOnTaskLaunch:与clearTaskOnLaunch相似,但它只对单独的activity起作用,而不是整个Task。 它可以结束任何Activity,包括栈底的Activity。 当它设置为true时,当前的Activity只在当前会话期间作为Task的一部分存在, 当用户按下Home键重新点击图标启动应用,它将不存在

2 . Activity 的启动流程

在Android系统中,有两种操作会引发Activity的启动:
1 用户点击应用程序图标时,Launcher会为我们启动应用程序的主Activity;
2. 应用程序的默认Activity启动起来后,它又可以在内部通过调用startActvity接口启动新的Activity,依此类推,每一个Activity都可以在内部启动新的Activity。
无论是通过点击应用程序图标来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都要借助于应用程序框架层的 ActivityManagerService服务进程 。(Service也是由ActivityManagerService进程来启动的。)在Android应用程序框架层中,ActivityManagerService是一个非常重要的接口,它不但负责 启动Activity和Service ,还负责 管理Activity和Service


Android应用程序框架层中的ActivityManagerService启动Activity的过程:


Activity启动的过程
       Step 1. 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过 Binder进程间通信 进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;
        Step 2. ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;
        Step 3. ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;
        Step 4. ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;
        Step 5. 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程;而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,因为新的Activity就在原来的Activity所在的进程中进行启动;
        Step 6. ActivityManagerServic调用ApplicationThread.scheduleLaunchActivity接口,通知相应的进程执行启动Activity的操作;
        Step 7. ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。
 
Android应用程序启动过程(点击应用程序图标)
       一. Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity;
       二. ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
       三. Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行;
       四. ActivityThread通过Binder进程间通信机制将一个 ApplicationThread类型的Binder对象 传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
       五. ActivityManagerService通过Binder进程间通信机制通知 ActivityThread ,现在一切准备就绪,它可以 真正执行Activity的启动 操作了。  
 
Android应用程序内部启动Activity过程(startActivity)
       一. 应用程序的MainActivity通过Binder进程间通信机制通知ActivityManagerService,它要启动一个新的Activity;
       二. ActivityManagerService通过Binder进程间通信机制通知MainActivity进入Paused状态;
       三. MainActivity通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就准备要在MainActivity所在的进程和任务中启动新的Activity了;
       四. ActivityManagerService通过Binder进程间通信机制通知MainActivity所在的 ActivityThread ,现在一切准备就绪,它可以 真正执行Activity的启动 操作了。
 
Android应用程序在新的进程中启动新的Activity
        函数 ActivityStack.startSpecificActivityLocked 函数中,决定一个Activity是在新的进程中启动还是在原有的进程中启动的因素有两个,一个是看这个 Activity的process属性的值 ,另一个是这个 Activity所在的应用程序的uid 。(应用程序的UID是由系统分配的,而Activity的process属性值,是可以在AndroidManifest.xml文件中进行配置的,如果没有配置,它默认就为application标签的process属性值,如果application标签的process属性值也没有配置,那么,它们就默认为应用程序的package名。)
        这里就是 根据processName和uid在系统查找是否已有相应的进程存在,如果已经有了,就会调用realStartActivityLocked来直接启动      Activity ,否则的话,就要 通过调用ActivityManagerService.startProcessLocked函数来创建一个新的进程,然后在新进程中启动这个Activity 了。对于前者,与Android应用程序内部启动Activity过程(startActivity)相同;而后者,与Android应用程序启动过程(点击应用程序图标)相同。


Activity扩展知识 :

Activity 如何在最近任务列表隐藏 :
android:excludeFromRecents="true"
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

如何退出Activity?如何安全退出已调用多个Activity的Application?
A. 在2.1之前,可以使用ActivityManager的restartPackage方法。它可以直接结束整个应用。在使用时需要权限android.permission.RESTART_PACKAGES。注意不要被它的名字迷惑。
B. 抛异常强制退出:该方法通过抛异常,使程序ForceClose。验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
C. 记录打开的Activity:每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
D: 发送特定广播:在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。E: 递归退出:在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。F: 在2.1之前,可以使用ActivityManager的restartPackage方法。它可以直接结束整个应用。在使用时需要权限android.permission.RESTART_PACKAGES。

Activity中 this、getApplicationContext和getActivity的区别
this:代表当前,在Activity当中就是代表当前的Activity,换句话说就是Activity.this 在Activity当中可以缩写为this.
getActivity()指的是在fragment当中调用得到他所在的Activity
getApplicationContext():生命周期是整个应用,应用摧毁,它才摧毁。


其他内容后续再进行补充

7. Activity 跳转过程中调用的方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值