章节索引 :

活动:Activity

从今天开始将会学习一个非常重要的概念——Android 四大组件,在 Android 中几乎所有的功能都和四大组件密不可分,而 Activity 是其中出场率最高的组件,也是对用户感知度最高的组件,当然也可以说是四大组件中最重要的一个组件。我们前面的绝大部分逻辑代码也都是在 Activity 中实现的,接下来详细介绍一下第一大组件——Activity。

1. Activity 的基本定义

An activity is a single, focused thing that the user can do. Almost all activities interact with the user, so the Activity class takes care of creating a window for you in which you can place your UI with setContentView. While activities are often presented to the user as full-screen windows, they can also be used in other ways: as floating windows (via a theme with android.R.attr.windowIsFloating set) or embedded inside of another activity (using ActivityGroup).

以上是摘自官方文档中对 Activity 的部分解释,用我不太流利的英语给大家翻译一下, 英语不太好的同学可以将就着看看:

Activity 提供给用户一个单一的、独立操作的用户界面,几乎所有的 Activity 都可以和用户进行交互,所以 Activity 类的主要功能是创建一个窗口来承载我们通过setContentView设置的 UI 界面,从而展示给用户。大部分场景下,Activity 会以全屏的形式占满手机屏幕,但是也支持浮窗或者内嵌的形式。

其实简而言之,Activity 就是一个用户界面,类似 Windows 系统里的窗口的概念,而第一个启动的 Activity,我们称之为主 Activity。

2. Activity 的生命周期

如果你学习过 C/C++ 或者 Java 开发应该很熟悉main()函数,没错,一切代码都是从main()函数开始的。在 Android 中也有类似的概念,每个 Android 应用程序都有一个主 Activity(启动 Activity),而其中的onCreate()方法就是所有代码的起点。

2.1 生命周期的各个流程

Android 系统为每个 Activity 设计了完备的生命周期,在各个不同的生命周期我们都可以做不同的工作,Activity 生命周期流程图如下:

Activity生命周期

上图中的每一个矩形框代表一个生命周期方法,Activity 一共有 7 个生命周期。当然我们在实际开发中并不需要全部都实现,只需根据具体需求在合适的时机去实现相应的生命周期方法即可,这就要求开发者对每个生命周期回调的时机和意义比较了解,下面我们来解读一下每个生命周期的调用时机:

  • onCreate():
    在 Activity 被创建的时候回调,也是 Activity 的第一个生命周期方法,在整个生命周期中只会执行一次。通常会在这里执行页面的初始化逻辑,大部分的 Activity 相关的代码都会在这里执行
  • onStart():
    当 Activity 对用户可见的时候回调,注意此时可能还不能交互,可以用来统计页面曝光
  • onResume():
    当 Activity 获取系统焦点的时候回调,此时已经可以和用户交互
  • onPause():
    当 Activity 暂停的时候回调,此时用户已经不能交互,并且暂停执行正常业务代码。通常这时候会回调下一个或者上一个 Activity 的onResume()
  • onStop():
    当 Activity 不可见的时候回调,此时结束曝光
  • onRestart():
    在“Stop”之后,再次回到 Activity 时触发此方法
  • onDestroy():
    此生命周期触发标志着 Activity 销毁,是最后一个生命周期,和onCreate()一样,只会调用一次,接着系统就会回收掉这部分资源

这 7 个生命周期不是单纯的线性运动,从上图可以看出除了第一个和最后一个:onCreate()onDestroy()之外,其他的都是可以反复循环的。

2.2 生命周期常见问题及误区

**另外要特别注意的,也是面试中非常容易被问到的一个经典问题:**从 Activity A 启动到 Activity B,再从 B 退回到 A,所经历的生命周期方法依次是哪几个?
大家可以先根据生命周期流转图及各生命周期的定义自行思考一下,分割线后给出答案。


我们来分析一下这个问题,首先是 Activity A 的启动:

A onCreate -> A onStart() -> A onResume()

到这里 A 就启动完毕了,接下来启动 Activity B,此时系统会将焦点移动到 B 上,故 A 的 onPause() 会被调用,接着创建 Activity B,那么流程是这样的:

A onPause() -> B onCreate() -> B onStart() -> B onResume()

此时 B 已经启动完毕,大家注意到 A 的onStop()自始至终还未执行,我们再次回忆一下onStop()的定义:“当 Activity 不可见的时候回调”。所以此时要分两种情况,如果 Activity B 是全屏的类型,那么在 B 启动之后系统会回调 Activity A 的 onStop();但是前面提到过,Activity可以是浮窗类型,此时 A 的onStop()则不会被回调,这是一个关键点,大家一定要记住!!

所以从 Activity A 跳转 Activity B 的生命周期触发顺序如下:

A onCreate -> A onStart() -> A onResume() -> 跳转 B -> A onPause() -> B onCreate() -> B onStart() -> B onResume() -> if (B is full screen) { A onStop() }

此时如果从 B 在返回到 A 的话,按照以上原理不难理解:

B onPause() -> A onRestart() -> A onStart() -> A onResume() -> B onStop() -> B onDestroy()

由于从 B 返回 A 需要销毁 B,所以此时不论 A 是否是全屏类型都会在 A 恢复之后依次调用 B 的onStop()onDestroy()。这个是面试必考题,大家务必掌握!


3. Activity 示例

关于 Activity 的使用其实从本教程的最开始就一直在用,我们通常都是将核心逻辑放在了onCreate()之中,比如setContentView设置布局样式,findViewById()获取布局中的控件实例,绑定监听器等等,所以 Activity 的用法相信大家并不陌生,这里主要是希望大家对除了 onCreate()方法之外的其他生命周期时机有所了解。我们将在 7 个生命周期中加入 Log 日志,观察一下各个生命周期的回调时机,编写 Activity 代码如下:

package com.emercy.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {
    String TAG = "Android Lifecycle";

    // 第一个被调用的方法,当 Activity 被创建时调用
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "The onCreate() event");
    }

    // Activity 可见
    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "The onStart() event");
    }

    // Activity 获取焦点,可交互
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "The onResume() event");
    }

    // Activity 失焦
    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "The onPause() event");
    }

    // Activity 停止,不可见
    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "The onStop() event");
    }

    // Activity 销毁
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "The onDestroy() event");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "The onRestart() event");
    }
}

编译运行,系统自动启动 MainActivity,此时观察 Logcat 输出:

Activity 启动

接着点击“Home”退出 Activity,然后切换回来,观察 Logcat 如下:

Activity 切换

最后点击 back 退出 App,再次观察 Logcat:

Activity 退出

通过 Logcat 可以观察到生命周期的跳转符合预期。

4. 小结

本节介绍了 Android 四大组件中的第一大组件,也是用的最多、责任最大的组件,其中最关键的是要掌握各个生命周期的调用时机及含义。
首先分析了 Activity 7 个生命周期的流转,以及各个生命周期的意义,接着通过一个示例配合具体的用户行为通过 Logcat 的形式打印了生命周期的变化,理论结合实际相信你会对 Activity 的生命周期有了更深的理解。中间还分享了一个关键点,也是面试中经常遇到的问题,希望大家牢牢掌握!

环境搭建,开发相关
Android 系统背景及结构概述 Android 开发环境搭建 Genymotion 的安装与使用 Android 工程解析及使用 Android 程序签名打包
常用 UI 布局
Android 的 UI 根基 View与View Android 线性布局 LinearLayout Android相对布局RelativeLayout Android 表格布局 TableLayout Android 网格布局 GridLayout Android 帧布局 FrameLayout Android绝对布局AbsoluteLayout
基础控件
Android 文本框 TextView Android 文本输入框 EditText 按钮 Button/ImageButton 选择框 RadioButton/Check 开关控件ToggleButton/Switch Android 图片控件 ImageView Android 进度条 ProgressBar Android 拖动条 SeekBar Android 评分条 RatingBar Android 滚动条 ScrollView 轮播滚动视图 ViewFlipper
Adapter 相关控件
Android 适配器 Adapter Android 列表控件 ListView Android 网格视图 GridView Android 下拉选择框 Spinner 自动补全文本框 AutoCompleteText 折叠列表 ExpandableListView
提示类控件
吐司提示:Toast 的使用方法 状态栏通知:Notification 对话框:AlertDialog 悬浮窗:PopupWindow
菜单类控件
菜单:Menu
其他控件
视频页面:ViewPager 侧滑菜单:DrawerLayout
事件处理机制
基于监听的事件处理机制 Handler 消息传递机制 触摸事件分发处理 AsyncTask:异步任务 Android 手势处理
Android 四大组件
活动:Activity 服务:Service 广播接收器:Broadcast Receiver 内容提供者 - Content Provider
数据存储
文件存储 SharedPreferences 存储 数据库:SQLite 的使用
网络编程
HTTP 使用详解 xml 数据解析 JSON 数据解析 网页视图:WebView Socket 网络接口
绘图与动画
图片资源:Drawable 位图:Bitmap
多媒体开发
媒体播放器:MediaPlayer 相机:Camera 音频录制:MediaRecorder
并发编程
多线程