1.什么是Activity
Activity是Android提供的四大组件之一,是进行Android开发必不可少的组件.Activity是一个界面的载体,它提供屏幕进行交互.可以把它与html页面进行类比,html页面由各种各样的标签组成,而Activity则可以由各种控件组成.每个Activity都会获得一个用于绘制其用户界面的窗口,窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上。
一个应用通常是由多个彼此松散联系的Activity组成,一般会指定应用中的某个Activity为主活动,也就是说首次启动应用时给用户呈现的Activity。将Activity设为主活动的方法,如下面代码所示需要在AndroidManifest文件中添加以下内容
<application>
....
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
....
</application>
当然Activity之间可以进行互相跳转,以便执行不同的操作。每当新Activity启动时,旧的Activity便会停止,但是系统会在堆栈也就是返回栈中保留该Activity。当新Activity启动时,系统也会将其推送到返回栈上,并取得用户的操作焦点。当用户完成当前Activity并按返回按钮时,系统就会从堆栈将其弹出销毁,然后回复前一Activity.
当一个Activity因某个新Activity启动而停止时,系统会通过该Activity的生命周期回调方法通知其这一状态的变化。Activity因状态变化每个变化可能有若干种,每一种回调都会提供执行与该状态相应的特定操作的机会
2.创建Activity
要创建Activity,必须创建Activity的子类。在子类中实现Activity在生命周期的各种状态之间转变时(例如创建 Activity、停止 Activity、恢复 Activity 或销毁 Activity 时)系统调用的回调方法。Android Studio中新建项目默认创建的代码为
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
onCreate()方法:必须实现的方法,系统在创建Activity时调用此方法。您应该在实现内初始化Activity的必要组件,必须在此方法调用setContentView(),用来定义Activity用户界面布局(XML文件)
3.在清单文件中声明Activity
每次新建的Activity都需要在AndroidManifest文件中添加如下内容,并将元素添加为元素的子项
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
4.启动Activity
作为主活动,在应用开启的时候就会系统创建,而用户不仅仅只需要主活动界面,用户需要界面的跳转,而界面的跳转也是其他活动界面(Activity)启动。
4.1 Activity启动方式
在Activity启动中涉及到Intent这个API,在Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。
Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。因此,可以将Intent理解为不同组件之间通信的“媒介”,专门提供组件互相调用的相关信息
Intent有七大属性:
- component(组件):目的组件
- action(动作):用来表现意图的行动
- category(类别):用来表现动作的类别
- data(数据):表示与动作要操纵的数据
- type(数据类型):对于data范例的描写
- extras(扩展信息):扩展信息
- Flags(标志位):期望这个意图的运行模式
显示启动
这应该用的是最多的一个启动方式了,先在AndroidManifest.xml里配置activity,然后进行如下操作:
Intent intent = new Intent(MainActivity.this,CloneActivity.class);
startActivity(intent);
隐式启动
它与显示启动最大区别就是不需要在Intent的实例化中传参, 但是需要在AndroidManifest.xml给该activity配置intentfilter属性,启动代码如下
<intent-filter>
<action android:name="com.mangoer.activityreview"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
Intent intent = new Intent();
intent.setAction("com.mangoer.activityreview");
startActivity(intent);
隐式启动的过滤过程如图

一般显示启动用于同一APP内,隐式启动用于启动APP外部活动,如果有多个组件被匹配成功,就会以对话框列表的方式让用户进行选择。每个Intent中只能指定一个action,但却能指定多个category;类别越多,动作越具体,意图越明确
在Intent添加类别可以添加多个类别,那就要求被匹配的组件必须同时满足这多个类别,才 能匹配成功。操作Activity的时候,如果没有类别,须加上默认类别
比如打开百度:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri data=Uri.parse("http://www.baidu.com");
intent.setData(data);
startActivity(intent);
有时候我们跳转到别的activity后,希望能够携带一些数据返回到原activity,那就需要用到startActivityForResult
4.2 Activity启动模式
启动模式允许你去定义如何将一个activity的实例和当前任务栈进行关联,有两种方式来定义启动模式
- 使用manifest文件:在manifest文件中声明一个activity的时候指定launchMode属性
- 使用Intent flag参数:当使用Intent启动activity的时候,可以在Intent中加入flag来指定新启动的activity如何与当前任务进行关联
如果一个被启动的activity在manifest里定义了启动模式,然后在使用Intent启动的时候也设置了flag定义启动模式,那么Intent中的定义模式将会覆盖manifest中的定义
在manifest定义启动模式
通过设置launchMode属性来定义,有四种可选参数:
- standard: 这也是默认启动模式,即标准模式;如果在该文件中声明activity的时候不指定这个参数值,这个activity就模式使用这种模式;它的意思是每启动一个activity都会重新创建一个该activity的实例加入到当前任务中,会走完整的生命周期函数,就算任务中已经存在了这个activity的实例还是会创建。这样就会出现上面说的一个activity在返回栈中存在多个实例,这其实是非常消耗资源的。
- singleTop: 即栈顶复用模式,这个中文翻译很有意思,给出了两个很重要的点,栈顶和复用;也就是说如果要启动的activity在返回栈内已经存在了一个实例并且还处于栈顶的位置,那么就不会在重新创建一个实例了,而是复用这个activity;复用体现在哪呢,就是调用这个activity的onNewIntent方法,而不会走onCreate-onStart-onResume这个创建逻辑了;如果这个activity不在栈顶,那么还是会重新创建的。这种模式一般运用场景是一个Activity被频繁推到栈顶的情况,比如IM聊天,有很多消息过来了,不可能每点击一个消息就去新建一个Activity;新闻推送,也不可能每次点击推送消息,就去新建一个Activity
-
singleTask: 即栈内复用模式,也是一种单例模式;当启动的activity如果在栈内有实例,不管在不在栈顶都会复用这个实例,将其置于栈顶,调用这个activity的onNewIntent方法,并且将其上面的所有activity进行出栈处理,全部销毁。
这里有个注意点:android系统会检测要启动的activity的affinity和当前任务的affinity是否相同,如果相同就会把这个activity放入到当前任务中,不同的话就会创建一个新的任务。而同一个程序中所有的activity的affinity默认都是相同的,不同的程序是不同的,这样启动别的应用的这种模式的activity会创建一个新的任务,启动自己应用的activity不会创建新的任务。这种模式运用场景比较少,一般用在比较特殊的页面,比如用户被签退了,需要重新跳转到登陆页面,这时候需要将之前的页面全部销毁,因为跟session相关的数据需要重新初始化
-
singleInstance: 即单例模式,即这个activity自己独享一个任务,所在的返回栈里面只有这个activity。
比如给activity2设置singleInstance模式,从activity1跳转到activity2,activity2跳转到activity3,这时候按返回键会返回到activity1.因为Activity2独自占用一个任务栈,而activity1和activity2共用一个任务栈
再举一个例子,Android系统内置的浏览器程序声明自己浏览网页的Activity始终应该在一个独立的任务当中打开,也就是通过在元素中设置"singleInstance"启动模式来实现的。这意味着,当你的程序准备去打开Android内置浏览器的时候,新打开的Activity并不会放入到你当前的任务中,而是会启动一个新的任务。而如果浏览器程序在后台已经存在一个任务了,则会把这个任务切换到前台,不会再重新创建。
使用Intent Flags 定义启动模式
使用方法就是在使用startActivity的时候构建Intent,对Intent加入一个flag来改变Activity与任务的关联模式
- FLAG_ACTIVITY_NEW_TASK: 当Intent对象包含这个标记时,系统会寻找或创建一个新的task来放置目标Activity,寻找时依据目标Activity的taskAffinity属性进行匹配,如果找到一个task的taskAffinity与之相同,就将目标Activity压入此task中,如果查找无果,则创建一个新的task,并将该task的taskAffinity设置为目标Activity的taskActivity,将目标Activity放置于此task。注意,如果同一个应用中Activity的taskAffinity都使用默认值或都设置相同值时,应用内的Activity之间的跳转使用这个标记是没有意义的,因为当前应用task就是目标Activity最好的宿主
- FLAG_ACTIVITY_SINGLE_TOP: 设置了这个flag,如果要启动的Activity在当前任务中已经存在了,并且还处于栈顶的位置,那么就不会再次创建这个Activity的实例,而是直接调用它的onNewIntent()方法;否则会再创建这个activity;这种flag和在launchMode中指定"singleTop"模式所实现的效果是一样的。
-
FLAG_ACTIVITY_CLEAR_TOP: 设置了这个flag,如果要启动的Activity在当前任务的栈顶,就会销毁这个实例并重新创建这个activity;如果不在栈顶,还是销毁已存在的实例并清空这个实例上面的所有activity,最后重新创建这个activity。
如果将Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP两个结合用,如果要启动的Activity已经存在任务栈而且不在栈顶,那么会清空这个activity以上的所有activity,并回调这个activity的onNewIntent,不会重新创建这个activity;如果处于栈顶,就直接回调onNewIntent
taskAffinity参数
affinity可以用于指定一个Activity更加愿意依附于哪一个任务,在默认情况下,同一个应用程序中的所有Activity都具有相同的affinity,所以,这些Activity都更加倾向于运行在相同的任务当中。当然了,你也可以去改变每个Activity的affinity值,通过元素的taskAffinity属性就可以实现了。
taskAffinity属性接收一个字符串参数,你可以指定成任意的值(经我测试字符串中至少要包含一个),但必须不能和应用程序的包名相同,因为系统会使用包名来作为默认的affinity值。
通常可以与allowTaskReparenting属性配合使用,设置为true时,Activity就拥有了一个转移所在任务的能力。具体点来说,就是一个Activity现在是处于某个任务当中的,但是它与另外一个任务具有相同的affinity值,那么当另外这个任务切换到前台的时候,该Activity就可以转移到现在的这个任务当中。
5. 结束Activity
通过调用Activity的**finish()方法来结束Activity还可以通过调用finishActivity()**结束之前启动的活动
关于finishActivity()的理解:
你通过 MainActivity 来启动 ActivityA (使用 startActivityForResult 方法),那么你在 MainActivity 这个类中需要重写 onActivityResult() 这个方法,
然后,你可以在 onActivityResult() 中通过 finishActivity() 方法去结束掉 ActivityA
6. 管理Activity生命周期
周期即活动从开始到结束所经历的各种状态。生命周期即活动从开始到结束所经历的各个状态。从一个状态到另一个状态的转变,从无到有再到无,这样一个过程中所经历的状态就叫做生命周期。
Activity本质上有四种状态:
- 运行(Active/Running): Activity处于活动状态,此时Activity处于栈顶,是可见状态,可以与用户进行交互
- 暂停(Paused): 当Activity失去焦点时,或被一个新的非全面屏的Activity,或被一个透明的Activity放置在栈顶时,Activity就转化为Paused状态。此刻并不会被销毁,只是失去了与用户交互的能力,其所有的状态信息及其成员变量都还在,只有在系统内存紧张的情况下,才有可能被系统回收掉
- 停止(Stopped): 当Activity被系统完全覆盖时,被覆盖的Activity就会进入Stopped状态,此时已不在可见,但是资源还是没有被收回
- 系统回收(Killed): 当Activity被系统回收掉,Activity就处于Killed状态,它所保存的信息和成员变量都不在了。
如果一个活动在处于停止或者暂停的状态下,系统内存缺乏时会将其结束(finish)或者杀死(kill)。这种非正常情况下,系统在杀死或者结束之前会调用**onSaveInstance()方法来保存信息,同时,当Activity被移动到前台时,重新启动该Activity并调用onRestoreInstance()**方法加载保留的信息,以保持原有的状态。
-
Activity 的整个生命周期发生在 onCreate() 调用与 onDestroy() 调用之间。
您的 Activity 应在 onCreate()中执行“全局”状态设置(例如定义布局),并释放 onDestroy()中的所有其余资源。例如,如果您的 Activity 有一个在后台运行的线程,用于从网络上下载数据,它可能会在onCreate() 中创建该线程,然后在onDestroy() 中停止该线程。
-
Activity 的可见生命周期发生在 onStart() 调用与 onStop() 调用之间。
在这段时间,用户可以在屏幕上看到 Activity 并与其交互。例如,当一个新 Activity 启动,并且此 Activity 不再可见时,系统会调用onStop()。您可以在调用这两个方法之间保留向用户显示 Activity 所需的资源。例如,您可以在onStart() 中注册一个 BroadcastReceiver 以监控影响 UI的变化,并在用户无法再看到您显示的内容时在 onStop()中将其取消注册。在 Activity 的整个生命周期,当 Activity 在对用户可见和隐藏两种状态中交替变化时,系统可能会多次调用 onStart() 和 onStop()。
-
Activity 的前台生命周期发生在 onResume() 调用与 onPause() 调用之间。
在这段时间,Activity 位于屏幕上的所有其他 Activity 之前,并具有用户输入焦点。Activity 可频繁转入和转出前台 — 例如,当设备转入休眠状态或出现对话框时,系统会调用 onPause()。由于此状态可能经常发生转变,因此这两个方法中应采用适度轻量级的代码,以避免因转变速度慢而让用户等待。
小结:
当Activity启动时,依次会调用onCreate(),onStart(),onResume(),而当Activity退居后台时(不可见,点击Home或者被新的Activity完全覆盖),onPause()和onStop()会依次被调用。当Activity重新回到前台(从桌面回到原Activity或者被覆盖后又回到原Activity)时,onRestart(),onStart(),onResume()会依次被调用。当Activity退出销毁时(点击back键),**onPause(),onStop(),onDestroy()**会依次被调用,到此Activity的整个生命周期方法回调完成。
参考:
- activity的四种状态说明
- Activity开发–掌握Activity隐式显示启动方法 scheme跳转协议 生命周期及启动模式配置
- Android Activity详解