活动Activity基础

一、Activity的生命周期

  首先,一个Activity代表一个页面。其次,Activity的 onCreate方法是页面的入口函数。更细心的读者也许已经知道调用startActivity方法可以跳转到下一个页面。
下面是Activity与生命周期有关的方法说明。

  1. onCreate:创建页面。把页面上的各个元素加载到内存中。
  2. onStart:开始页面。把页面显示在屏幕上。
  3. onResume:恢复页面。让页面在屏幕上活动起来,例如开启动画、开始任务等。
  4. onPause:暂停页面。让页面在屏幕上的动作停下来。
  5. onStop:停止页面。把页面从屏幕上撤下来。
  6. onDestroy:销毁页面。把页面从内存中清除掉。
  7. onRestart:重启页面。重新加载内存中的页面数据。

1.页面之间的跳转

  1. 首先打开页面ActJumpActivity,调用方法的顺序为:本页面onCreate→onStart→onResume。
  2. 从ActJumpActivity跳转到ActNextActivity,调用方法的顺序为:上一个页面onPause→下一个页面 onCreate→onStart→onResume→上一个页面onStop。
  3. 从ActNextActivity回到ActJumpActivity(按返回键或在代码中调用finish方法),调用的方法顺序为: 下一个页面onPause→上一个页面onRestart→onStart→onResume→下一个页面onStop→onDestroy。
  4. 总体上是跳转 前的页面先调用onPause方法,然后跳转后的页面依次调用 onCreate/onRestart→onStart→onResume,最后跳转前的页面调用onStop方 法(若返回上级页面,则下级页面还需调用onDestroy方法)

2. 竖屏与横屏的切换

  1. 竖屏与横屏似乎在每次切换时页面都要重新创建。
  2. 无论是竖屏切换到横屏,还是横屏切换到竖屏,都是原屏幕的页面从onPause 到onStop再到onDestroy一路销毁,然后新屏幕的页面从onCreate到onStart再到onResume一路创建而来。

3. 按HOME键与返回App

android 后台切换生命周期 android activity跳转生命周期_bundle


从日志截图可以看到,此时测试页面的生命周期是典型的从活动状态变为暂停状态(回到桌面时)再 到活动状态(返回App页面时)。

二、使用Intent传递消息

  Intent是各个组件之间信息 沟通的桥梁,既能在Activity之间沟通,又能在Activity与Service之间沟通,也能在Activity与Broadcast之间 沟通。总而言之,Intent用于处理Android各组件之间的通信,完成的工作主要有3部分:
(1)Intent需标明本次通信请求从哪里来、到哪里去、要怎么走。
(2)发起方携带本次通信需要的数据内容,接收方对收到的Intent数据进行解包。
(3)如果发起方要求判断接收方的处理结果,Intent就要负责让接收方传回应答的数据内容。

为了做好以上工作,就要给Intent配上必须的装备,Intent的组成部分见表3-5。

android 后台切换生命周期 android activity跳转生命周期_数据_02


表达Intent的来往路径有两种方式,一种是显式Intent,另一种是隐式Intent。

1. 显式Intent,直接指定来源类与目标类名,属于精确匹配。

在声明一个Intent对象时,需要指定两个参数,第一个参数表示跳转的来源页面,第二个参数表示接下 来要跳转到的页面类。具体的声明方式有如下3种:
(1)在构造函数中指定,示例代码如下:
Intent intent = new Intent(this, ActResponseActivity.class); // 创建一个目标确定的意图
(2)调用setClass方法指定,示例代码如下:
Intent intent = new Intent(); // 创建一个新意图
intent.setClass(this, ActResponseActivity.class); // 设置意图要跳转的活动类
(3)调用setComponent方法指定,示例代码如下:
Intent intent = new Intent(); // 创建一个新意图
ComponentName component = new ComponentName(this, ActResponseActivity.class); intent.setComponent(component); // 设置意图携带的组件信息

2. 隐式Intent,没有明确指定要跳转的类名,只给出一个动作让系统匹配拥 有相同字串定义的目标,属于模糊匹配。

因为我们常常不希望直接暴露源码的类名,只给出一个事先定义好的名称,这样大家约定俗成、按图索骥就好,所以隐式Intent起到了过滤作用。

android 后台切换生命周期 android activity跳转生命周期_android 后台切换生命周期_03


这个动作名称通过setAction方法指定,也可以通过构造函数Intent(String action)直接生成Intent对象。

由于动作是模糊匹配,因此有时需要更详细的路径,比如知道某人住在天通苑小区,并不能直接找到 他家,还得说明他住在天通苑的哪一期、哪号楼、哪一层、哪一个单元。

Uri和Category便是这样的路径与门类信息

Uri数据可通过构造函数Intent(String action,Uri uri)在生成对象时一起指定,也可通过setData方法 指定(setData这个名字有歧义,实际就是setUri); Category可通过addCategory方法指定,之所以用add而不 用set方法,是因为一个Intent可同时设置多个Category,一起进行过滤。

下面是一个调用系统拨号程序的例子,其中就用到了Uri:
Intent intent = new Intent(); // 创建一个新意图
intent.setAction(Intent.ACTION_CALL); // 设置意图动作为直接拨号
Uri uri = Uri.parse(“tel:” + phone); // 声明一个拨号的Uri
intent.setData(uri); // 设置意图前往的路径
startActivity(intent); // 启动意图通往的活动页面

隐式Intent还用到了过滤器的概念,即把不符合匹配条件的过滤掉,剩下符合条件的按照优先顺序调用。

创建一个Android工程,AndroidManifest.xml里的intent-filter就是XML中的过滤器。

activity节点下面便设置了actioncategory的过滤条件。其中, android.intent.action.MAIN表示App的入口动作,android.intent.category.LAUNCHER表示在App启动时调用

三、向下一个Activity传递参数

Intent的setData方法只指定到达目标的路径,并非本次通信所携带的参数信息,真正的参数信息存放在Extras中。

不过只是调用putExtra方法显然不好管理,像送快递一样大小包裹随便扔,不但找起来不方便,丢了也难以知道。所以Android引入了Bundle概念,可以把 Bundle理解为超市的寄包柜或快递收件柜,大小包裹由Bundle统一存取,方便又安全。

Bundle内部用于存放数据的实质结构是Map映射,可添加元素、删除元素,还可判断元素是否存在。开 发者把Bundle全部打包好只需调用一次putExtras方法,把Bundle全部取出来也只需调用一次getExtras方法。

下面是前一个页面向后一个页面发送请求数据的代码:

Intent intent = new Intent(MainActivity.this, FirstActivity.class); // 创建一个目标确定的意图
 Bundle bundle = new Bundle(); // 创建一个新包裹
 bundle.putString(“name”, “张三”); // 往包裹存入一个字符串
 bundle.putInt(“age”, 30); // 往包裹存入一个整型数
 bundle.putDouble(“height”, 170.0f); // 往包裹存入一个双精度数
 intent.putExtras(bundle); // 把快递包裹塞给意图
 startActivity(intent); // 启动意图所向往的活动页面

下面是后一个页面接收前一个页面请求数据的代码:

Intent intent = getIntent(); // 获取前一个页面传来的意图
 Bundle bundle = intent.getExtras(); // 卸下意图里的快递包裹
 String name = bundle.getString(“name”, “”); // 从包裹中取出字符串
 int age = bundle.getInt(“age”, 0); // 从包裹中取出整型数
 double height = bundle.getDouble(“height”, 0.0f); // 从包裹中取出双精度数

四、向上一个Activity返回参数

  Intent有时只把请求数据发送到下一个页面就行,有时还要处理下一个页面的应答数据(通常发生在下一个页面返回到上一个页面时)。如果只把请求数据发送到下一个页面,前一个页 面调用startActivity方法就可以;如果还要处理一下个页面的应答数据,此时就得分多步处理,详细步骤如下:

步骤01 前一个页面打包好请求数据,调用方法startActivityForResult(Intent intent, int requestCode),表示需要处理结果数据,第二个参数表示请求编号,用于标识每次请求的唯一性

步骤02 后一个页面接收请求数据,进行相应处理。

步骤03 后一个页面在返回前一个页面时,打包应答数据并调用setResult方法返回信息setResult的第 一个参数表示应答代码(成功还是失败),代码示例如下:

Intent intent = new Intent(); // 创建一个新意图
 Bundle bundle = new Bundle(); // 创建一个新包裹
 bundle.putString(“job”, “码农”); // 往包裹存入一个字符串
 intent.putExtras(bundle); // 把快递包裹塞给意图
 setResult(Activity.RESULT_OK, intent); // 携带意图返回前一个页面
 finish(); // 关闭当前页面

步骤04 前一个页面重写方法onActivityResult,该方法的输入参数包含请求编号应答代码请求编号用于判断对应哪次请求应答代码用于判断后一个页面是否处理成功。然后对应答数据进行解包处理, 代码示例如下:

android 后台切换生命周期 android activity跳转生命周期_android_04