Android安全/开发基础--2--四大组件之活动(Activity)

版权声明:本文为博主原创文章,转载本站文章请注明作者和出处,请勿用于任何商业用途。 https://blog.csdn.net/wutianxu123/article/details/82832367

2-1、Activity的基本理论

Activity定义:是一种可以包含用户界面的组件,主要用于和用户进行交互。

Android程序设计讲究逻辑和视图分离,最好每一个活动都能对应一个布局,布局就是用来显示界面内容的。使用一个Activity集中于单个任务并为各个任务创建不同的Activity是最佳的。即每个页面只分管一个任务。

组件的重复调用有两个主要的好处。第一,有助于减少漏洞,因为有较少的代码重复。第二,使应用程序更加安全,因为不同的组件之间有较少的数据共享。

声明下面没有Intent-Filter的Activity是一个私有的Activity,将只通过指定其明确的文件名来调用。所有的Activity可以被自定义权限保护,在声明完android:name后就声明android:premission。

当系统配置发生改变后,Activity会被重新创建,如果不想系统重新创建Activity,即给Activity指定android:configChanges属性。不同属性之间用”|”连接。如:

android:configChange=”orientation”     //屏幕旋转时不重建Activity

独立的屏幕尺寸修饰符:

修饰符格式 描述
wXXXdp 有效宽度:宽度大于或等于XXX dp
hXXXdp 有效高度:高度大于或等于XXX dp
swXXXdp 最小宽度:宽度或高度(两者中最小的那个)大于或等于XXX dp

2-2、Activity的生命周期

Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称为返回栈(Back Stack)。每个Activity在生命周期中最多可能有4种状态:

1、运行状态。位于返回栈的栈顶时,即处于运行状态。
2、暂停状态。不再处于栈顶位置但任然可见时,即处于暂停状态。因为并不是每个活动都占满屏幕。
3、停止状态。不再处于栈顶位置且完全不可见时,即处于停止状态。即进入后台程序。
4、销毁状态。从栈中移除即变成了销毁状态。

2-3、活动的启动模式

在AndroidManifest.xml中通过标签指定android:launchMode属性来选择启动模式。

1、standard:标准模式。是默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。在该模式下,每启动一个新活动它就会返回栈中入栈,并处于栈顶位置。对于该模式启动的活动,不管是否在栈中已经存在,每次启动都会创建该活动的一个新的实例。ABC-ABCC。

2、singleTop:栈顶复用模式。在该模式下启动活动时,如果返回栈的栈顶已经是该活动,则直接使用它,不再创建新的活动实例。如果不是位于栈顶,仍然重建。ABC-ABC,栈顶复用,不变。

3、singleTask:栈内复用模式。在该模式下启动活动时,系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例。并把这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。ACBD-AC,栈内复用,BD出栈。

扫描二维码关注公众号,回复: 3410821 查看本文章

4、singleInstance:单实例模式。在该模式下启动活动时,系统会启用一个新的返回栈来管理这个活动。由于栈内复用的特性,后续的请求均不会创建新的Activity。用来实现共享活动实例。

另一种情况是通过在Intent中设置标志位intent.addFlags()来选择启动模式。举例如下:

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

FLAG_ACTIVITY_NEW_TASK:是为Activity指定singleTask模式
FLAG_ACTIVITY_SINGLE_TOP:是为Activity指定singleTop模式
FLAG_ACTIVITY_CLEAR_TOP:需要和FLAG_ACTIVITY_NEW_TASK配合使用,具有此标志位的Activity,当它启动时,在同一个任务中所有位于它上面的Activity都要出栈。注意,不能和上面同功能的模式划等号。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标记的Activity不会出现在历史Activity的列表中。当不希望通过历史列表回到我们的Activity的时候使用。

2-4、探讨Activity启动

1、Activity组件的启动方式分为显式和隐式两种

显式启动的Activity组件:必须事先知道用来实现它们的类的名称。

隐式启动的Activity组件:只需要知道它们的组件名称即可,而不需要知道它们是由哪一个类来实现的。

区别:系统是根据类名还是根据组件名称来找到它们的,从软件工程的角度来看,隐式启动Activity组件可以减少Android应用程序组件之间的依赖。

2、根Activity组件的启动过程

MainActivity组件是由Launcher组件来启动的,而Launcher组件又是通过Activity管理服务ActivityManagerService来启动MainActivity组件的。由于MainActivity组件、Launcher组件和ActivityManagerService是分别运行在不同进程中的,因此,MainActivity组件启动过程就涉及到了三个进程。这三个进程是通过Binder进程间通信机制来完成MainActivity组件的启动过程的。

Launcher组件启动MainActivity组件的过程如下:

1、Launcher组件向ActivityManagerService发送一个启动MainActivity组件的进程间通信请求。

2、ActivityManagerService首先将要启动的MainActivity组件的信息保存下来,然后再向Launcher组件发送一个进入中止状态的进程间通信请求。

3、Launcher组件进入到中止状态后,就会向ActivityManagerService发送一个已进入中止状态的进程间通信请求,以便ActivityManagerService可以继续执行启动MainActivity组件的操作。

4、ActivityManagerService发现用来运行MainActivity组件的应用程序进程不存在,因此,它就会先启动一个新的应用程序进程。

5、新的应用程序进程启动完成之后,就会向ActivityManagerService发送一个启动完成的进程间通信请求,以便于ActivityManagerService可以继续执行启动MainActivity组件的操作。

6、ActivityManagerService将第2步保存下来的MainActivity组件的信息发送给第4步创建的应用程序进程,以便于它可以将MainActivity组件启动起来。

在默认情况下,目标Activity组件是与源Activity组件运行在同一个任务中的,然而如果源Activity组件将目标Activity组件的启动标志值的FLAG_ACTIVITY_NEW_TASK位设置为1,并且源Activity不需要知道目标Activity组件的运行结果,那么ActivityManagerService就会将目标Activity组件运行在另外一个不同的任务中。Activity组件的android:taskAffinity属性用来描述它的一个专属任务。

3、子Activity组件在进程内的启动过程

MainActivity组件启动子Activity组件的过程如下:

1、MainActivity组件向ActivityManagerService发送一个启动子Activity组件的进程间通信请求。

2、ActivityManagerService首先将要启动的子Actvity组件的信息保存下来,然后再向MainActivity组件发送一个进入中止状态的进程间通信请求。

3、MainActivity组件进入到中止状态之后,就会向ActivityManagerService发送一个已进入中止状态的进程间通信请求,以便ActivityManagerService可以继续执行启动子Activity组件的操作。

4、ActivityManagerService发现用来运行子Activity组件的应用程序进程已经存在,因此它就会将第2步保存下来的子Activity组件信息发送给该应用程序进程,以便它可以将子Activity组件启动起来。

由于ActivityManagerService不需要创建一个新的应用程序进程来启动子Activity组件,因此,子Activity组件的启动过程要比MainActivity组件的启动过程简单。

4、子Activity组件在新进程中的启动过程

以下的子Activity组件代表在新进程中启动的子Activity:

1、MainActivity组件向ActivityManagerService发送一个启动子Activity组件进程间通信请求。

2、ActivityManagerService首先将要启动的子Actvity组件的信息保存下来,然后再向MainActivity组件发送一个进入中止状态的进程间通信请求。

3、MainActivity组件进入到中止状态之后,就会向ActivityManagerService发送一个已进入中止状态的进程间通信请求,以便ActivityManagerService可以继续执行启动子Activity组件的操作。

4、ActivityManagerService发现用来运行子Activity组件的应用程序进程不存在,因此它就会先启动一个新的应用程序进程。

5、新的应用程序进程启动完成之后,就会向ActivityManagerService发送一个启动完成的进程间通信请求,以便ActivityManagerService可以继续执行启动子Activity组件的操作。

6、ActivityManagerService将第2步保存下来的子Activity组件的信息发送给第4步创建的应用程序进程,以便于它可以将子Activity组件启动起来。

2-5、Activity的生存期:共定义了7个回调方法

1、完整生存期

onCreate():在活动第一次创建的时候调用,该方法中主要完成初始化操作。
onDestroy():在活动被销毁之前调用,之后活动变为销毁状态,该方法主要完成释放内存操作。

2、可见生存期

onStart():在活动由不可见变为可见的时候调用,该方法主要对资源进行加载。
onStop():在活动完全不可见的时候调用,该方法主要对资源进行释放。

3、前台生存期
onResume():在活动准备好和用户交互的时候进行调用,此时活动处于运行状态。
onPause():该方法在系统准备去启动或者恢复另一个活动的时候调用,主要对资源进行释放。

4、onRestart()

在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。

2-6、活动回收

Bundle是存储字符串键与限定类型值之间映射关系(键-值对)的一种结构。比如使用putString()方法保存字符串,使用putInt()方法保存整型数据。在Bundle中存储和恢复的数据类型只能是基本类型(primitive type)以及可以实现Serializable或Parcelable接口的对象。

当活动进入停止状态后,极容易被系统回收,如果被回收了再打开则之前活动上的数据都会销毁重建,为解决活动被回收时临时数据得不到保存,Android提供了onSaveInstanceState()和onRestoreInstanceState()来存储和恢复数据,细节如下:

当系统配置发生变化后(比如竖屏突变为横屏),Activity会被销毁,其onPause()、onStop()、onDestroy()均会被调用,同时由于Activity是在异常情况下终止的,系统会调用onSaveInstanceState()来保存当前Activity的状态。注意,Activity正常终止情况下不会调用这个方法。当Activity被重新创建后,系统会调用onRestoreInstanceState(),并且把Activity销毁时onSaveInstanceState()方法所保存的Bundle对象作为参数同时传递给onRestoreInstanceState()和onCreate()方法。因此,我们通过onRestoreInstanceState()和onCreate()方法来判断Activity是否被重建了,如果重建了,就可以取出之前保存的数据并恢复。

2-7、双版面主从用户界面

在手机设备上, CrimeListActivity生成的是单版面(single-pane)布局。在平板设备上,为了同时显示主从视图,我们需要它生成双版面(two-pane)布局。

要实现双版面布局,需完成如下任务:

1、修改SingleFragmentActivity,不再硬编码实例化布局。CrimeListActivity是SingleFragmentActivity的子类。
2、创建包含两个fragment容器的布局。
3、修改CrimeListActivity,实现在手机设备上实例化单版面布局,在平板设备上实例化双版面布局。

别名资源是一种指向其他资源的特殊资源。它存放在res/values/目录下,并按照约定定义在refs.xml文件中。接下来的任务就是让CrimeListActivity基于不同的设备使用不同的布局文件。

要委托工作任务给托管activity,通常的做法是由fragment定义名为Callbacks的回调接口。回调接口定义了fragment委托给托管activity处理的工作任务。任何打算托管目标fragment的activity都必须实现它。

2-8、Activity的生命周期图

就整个生命周期来说,onCreate()和onDestroy()是配对的,分别标识着Activity的创建和销毁,并且只可能有一次调用。从Activity是否可见来说,onStart()和onStop()是配对的,随着用户的操作或者设备屏幕的点亮和熄灭,这两个方法可能被调用多次。从Activity是否在前台来说,onResume()和onPause()是配对的,随着用户操作或者设备屏幕的点亮和熄灭,这两个方法可能被调用多次。

注意,当前Activity为A,打开一个新的Activity B,A的onPause()先执行,B的onResume后执行。

Activity的生命周期图如下:

在这里插入图片描述

2-9、Activity:应用程序的交互界面组件。每一个Activity提供一个屏幕

私有Activity。不能由其他程序启动的Activity,是最安全的Activity。

1、不声明taskAffinity。(在同一个应用中,启动的Activity都在同一个Task中,它们在该Task中度过自己的生命周期。如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值)

2、不声明LaunchMode。(launchMode在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task)

3、设置exported属性为false
4、保证Intent发送时的安全性,确定Intent是来自本应用程序
5、使用显式Intent与指定的类的方式来调用一个Activity
6、敏感的信息放置在extra中发送

公共Activity。最常见的Activity,任意程序都能启动此类Activity

1、设置exported的属性值为true
2、接到Intent的时候注意小心处理
3、Finish的时候别在Intent中放置一些敏感的信息

伙伴Activity。只能有伙伴应用程序才能启动的Activity

1、不声明taskAffinity
2、不声明LaunchMode
3、不添加intent-fillter设置exported属性值为true
4、使用白名单机制验证应用签名
5、不要在Intent中放置一些敏感信息

内部Activity。此类Activity只能由自身应用程序使用

1、不声明taskAffinity
2、不声明LaunchMode
3、不声明intent-fillter设置exported属性值为true
4、定义Activity的签名权限为signature
5、验证签名

猜你喜欢

转载自blog.csdn.net/wutianxu123/article/details/82832367
今日推荐