Android/Activity,Intent,Context总结

一、简介

Activity,即活动Android四大组件之一。

Android四大组件:
Activity, Service, BroadcastReciver, ContentProvider.

一个应用通常由多个彼此松散联系的 Activity组成。

当新 Activity启动时,前一Activity便会停止,但系统会在返回栈中保留该Activity。 当新Activity启动时,系统会将其推送到返回栈上,并取得用户焦点。 返回栈遵循后进先出堆栈机制。

注意:返回栈是每个任务单独含有的,与任务管理器不同

二、生命周期

Activity的生命周期相关方法包括:

  • onCreate():创建时调用
  • onStart():处于可见状态调用
  • onResume(): 处于焦点时调用(初次启动、弹窗消失)
  • onPause(): 失去焦点但依旧可见时调用(出现弹窗)
  • onStop(): 不在最顶层不可见时调用(新activity、home键)
  • onDistory: 退出时调用(back键)

官方文档描述:

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生命周期:

当一个Activity启动另一个Activity时,有如下顺序:

  1. Activity A 的 onPause() 方法执行。
  2. Activity B 的 onCreate()、onStart() 和 onResume() 方法依次执行。(Activity B 现在具有用户焦点。)
  3. 如果 Activity A 在屏幕上不再可见,则其 onStop() 方法执行。

三、任务与状态保存

  • 一个返回栈即一个任务(即使他们可能来自不同的应用)。
  • 当用户按下back键,栈顶的Activity被销毁,前一个Activity恢复执行(并恢复其UI状态(滚动位置与已输入表单的文本))。
  • 当用户按下Home键或开启新任务,原任务执行onStop(),保存原有的返回栈并后台运行。再次启动则回到前台,原有的返回栈不变。
  • 当一个Activity不在前台时(即onStop()),系统可能会为了回收资源完全销毁该Activity。故应该在Activity中实现onSaveInstanceState()来保留其状态。并且若用户长时间离开任务,系统会清除除根Activity外的所有Activity。可用属性修改此行为。具体见官方文档

onSaveInstanceState()的用法:

系统会先调用 onSaveInstanceState(),然后再使 Activity 变得易于销毁。系统会向该方法传递一个 Bundle,您可以在其中使用 putString() 和 putInt() 等方法以名称-值对形式保存有关 Activity 状态的信息。然后,如果系统终止您的应用进程,并且用户返回您的 Activity,则系统会重建该 Activity,并将 Bundle 同时传递给 onCreate() 和 onRestoreInstanceState()。您可以使用上述任一方法从 Bundle 提取您保存的状态并恢复该 Activity 状态。如果没有状态信息需要恢复,则传递给您的 Bundle 是空值。

默认实现通过调用View.onSaveInstanceState()保存具有id的视图的状态,并保存其id。重写此方法时注意调用它的超类来保存数据。

四、启动模式

Android提供4种启动方式:

  • 标准模式(Standard)
  • 栈顶复用模式(SingleTop):在顶部启动自身时不再实例化新的Activity。
  • 栈内复用模式(SingleTask):存在这样的Activity(无论在不在这一个任务中),则将它的任务拿来放在栈顶。
  • 单例模式(SingleInstance):该Activity所在任务中只有自身,打开新的Activity都是新建单独的栈。

以上模式皆在AndroidMainifest launchMode 属性定义。
或使用intent设置标记位

1
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

此方法优先级高于AndroidMainifest

Intent 标志作用
FLAG_ACTIVITY_SINGLE_TOP与SingleTop相同
FLAG_ACTIVITY_NEW_TASK与SingleTask相同
FLAG_ACTIVITY_CLEAR_TOP销毁当前任务顶部的所有 Activity,使所需Activity置顶
FLAG_ACTIVITY_CLEAR_TOP 通常与 FLAG_ACTIVITY_NEW_TASK 结合使用。

五、数据传递与返回

Android使用Intent在Activity中启动新Activity,分为显式与隐式两种.

显式:
1
2
Intent intent = new Intent(Context,Class);
startActivity(intent);
隐式:

根据操作让其他适合的应用处理它,如分享操作.

创建隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。 如果 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并向其传递 Intent 对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。通过为 Activity 声明 Intent 过滤器,可以使其他应用能够直接使用某一特定类型的 Intent 启动 Activity.

1
2
3
4
5
6
7
8
9
10
// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}

启动Activity可以带有操作,如ACTION_VIEW, ACTION_SEND. 通过setAction()设置其操作常量,前者为调用其他应用显式某信息,后者为通过Intent共享数据。此外还有ACTION_EDIT等.

数据传递:

设置数据uri调用setData(),设置MIME类型调用setType(),同时设置时务必调用setDataAndType().
Intent还可以携带特定的Extra。如上例中使用putExtras(),每个方法均接受两个参数:键名与值。

启动Activity更常用的方法:

为了使启动Activity更加稳定安全,一般可以在要启动的Activity中写一个方法,在该方法内实现intent与启动。则在要启动它时只需在上一个Activity中调用该方法并传入必需的参数即可。

1
2
3
4
5
6
public static void actionStart(Context context, String data){
Intent intent = new Intent(context,SecondActivity.class);
intent.putExtra("text",data);
context.startActivity(intent);
}
// 所需参数为Context与Extra的String.

Activity中调用方法:

1
SecondActivity.actionStart(Context,String;

即可启动新的Activity。

构建Intent过滤器:

在清单文件中使用 <intent-filter>元素为每个应用组件声明一个或多个 Intent 过滤器。
使用一下一个或多个指定要接受的Intent类型。

<action>:
在 name 属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。

<category>:
在 name 属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。必须将CATEGORY_DEFAULT 设置为category的一部分,否则Intent将不会对他解析

<data>:
使用一个或多个指定数据 URI 各个方面(scheme、host、port、path 等)和 MIME 类型的属性,声明接受的数据类型。
例如:

1
2
3
4
5
6
7
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>

六、处理配置变更

运行时变更包括以下类型,在发生这些变更时系统会重启正在运行的应用,并通过onSaveInstanceState()恢复之前状态。

如果不希望这样做,有两种选择:

1.当配置改变时维持一个对象

如果数据很多,它们不会都放bundle中,那么加载起来就会影响到用户体验。

2.阻止系统重启,自己处理

这种技术应该被视为最后的手段,对于大多数应用程序不建议使用。
具体方法参考官方文档,遇到相关问题再进行总结。

七、Context

在Android开发中经常遇到Context这一抽象类。通俗来说,Context便是场景,有时也被译作上下文。它包括这个应用、活动、服务、广播接收器、内容提供器的所有资源。
为了让系统能够顺利回收内存,避免内存泄漏,就需要在传Context时使用当前组件类型的Context。

后记

写总结虽然累了些,但能对知识查漏补缺、建立体系,加深理解并且可供以后的查阅复习,实为一种好方法。
可就是太累了啊!!!两天一篇效率好低…
参考:
官方文档:https://developer.android.com/guide/components/activities?hl=zh-cn
《Android基础:最易懂的Activity启动模式详解》:https://www.jianshu.com/p/399e83d02e33
《Android插件化基础2—-理解Context》:https://www.jianshu.com/p/e6ce2d03f8f9