Activity生命周期:掌握onCreate、onStart、onResume、onPause、onStop、onDestroy的调用时机与场景

说实话,Activity生命周期这个话题,几乎是每个Android开发者入行时最先接触的概念。但有意思的是,我面试过不少自称“三年经验”的候选人,聊到生命周期细节时,往往只能背出六个方法名,真要问“onPause和onStop到底谁先谁后?什么场景下会只走onPause不走onStop?”就卡壳了。

嗯,今天咱们就把这六个回调方法彻底掰扯清楚。我会结合自己这些年踩过的坑,帮你建立起一套“肌肉记忆”——以后写代码时,不用查文档也能条件反射地知道该在哪个生命周期里做什么事。

一、生命周期全景图:六个回调,三种状态

先看一张我手绘的流程图,把整个生命周期串起来。你想想看,一个Activity从创建到销毁,就像一个人的一生:出生、成长、工作、暂停、休眠、离世。每个阶段都有对应的回调方法。

Activity 生命周期流转图 onCreate() onStart() onResume() onPause() onStop() onDestroy() 创建阶段 可见阶段(不可交互) 可见阶段(可交互) 部分可见 → 不可见 完全不可见 销毁阶段 返回前台 回到前台

这张图我建议你保存下来。每次写Activity时瞄一眼,心里就有数了。我个人习惯把这张图打印出来贴在工位上,带新人时直接指着图讲,比说一万句都管用。

二、逐个击破:每个回调的“前世今生”

1. onCreate() —— 出生证明

这是Activity的“第一声啼哭”。系统创建Activity时调用,且只调用一次。说白了,这里就是做初始化工作的最佳场所。

典型用途:

  • 调用 setContentView() 加载布局
  • 初始化 View 引用(findViewById)
  • 初始化 ViewModel、LiveData 等架构组件
  • 恢复 savedInstanceState 中的状态
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 恢复状态
    if (savedInstanceState != null) {
        String userName = savedInstanceState.getString("user_name");
        // 恢复用户输入等
    }
    
    // 初始化ViewModel
    mViewModel = new ViewModelProvider(this).get(MyViewModel.class);
}

我的经验:千万别在onCreate里做耗时操作!我记得有一次接手一个老项目,前任在onCreate里直接做了网络请求,结果每次旋转屏幕都要等两三秒。后来改成在onResume里触发加载,配合缓存,体验好多了。

2. onStart() —— 准备登场

Activity从“不可见”变为“可见”时调用。注意,此时Activity虽然可见,但还不能与用户交互。嗯,你可以理解为演员已经站到了舞台上,但幕布还没拉开。

我在项目中遇到过一个问题:有个页面需要在显示时刷新数据,我一开始写在onResume里,结果每次从别的Activity返回都会刷新,太频繁了。后来改成在onStart里做,配合一个“是否需要刷新”的标记位,完美解决。

3. onResume() —— 正式开演

Activity进入前台,可以与用户交互了。这是用户真正“使用”你的页面的时刻。

典型用途:

  • 开始动画、视频播放
  • 注册广播接收器、传感器监听
  • 打开相机预览
@Override
protected void onResume() {
    super.onResume();
    // 开始播放视频
    if (mVideoView != null && !mVideoView.isPlaying()) {
        mVideoView.start();
    }
    // 注册定位监听
    mLocationManager.requestLocationUpdates(...);
}

注意:onResume和onPause是成对出现的。你想想看,如果用户在玩游戏时突然来电话,游戏画面应该暂停——这就是onPause要做的事。我曾经在做一个直播App时,忘记在onPause里停止摄像头预览,结果用户切到后台后摄像头还在亮着,被用户投诉“偷拍”……

4. onPause() —— 暂停时刻

当另一个Activity(比如来电界面、系统弹窗)覆盖当前Activity时调用。此时Activity仍然部分可见,但已经失去焦点。

关键点:onPause的执行时间非常短(Android官方建议在几百毫秒内完成),因为新Activity要等onPause执行完才能启动。所以,不要在onPause里做耗时操作

避坑指南:我曾经在onPause里做数据库写入操作,结果导致新Activity启动卡顿。后来把数据保存挪到onStop里做,或者用WorkManager异步处理,流畅多了。

5. onStop() —— 退居幕后

Activity完全不可见时调用。比如用户按了Home键,或者启动了新的全屏Activity。

这里有个容易混淆的点:onPause和onStop的区别。说白了,onPause是“部分可见”,onStop是“完全不可见”。举个例子:

  • 来电弹窗(非全屏)→ 只走onPause,不走onStop
  • 按Home键 → 先onPause,再onStop
  • 启动新全屏Activity → 先onPause,再onStop

典型用途:

  • 保存草稿、持久化数据
  • 停止动画、释放资源
  • 注销广播接收器

6. onDestroy() —— 最后的告别

Activity被销毁前调用。可能是用户主动finish(),也可能是系统为了回收内存而销毁。

重要提醒:系统可能不会调用onDestroy!比如用户强制杀进程、系统内存极度紧张时,Activity可能直接被“处决”,连个招呼都不打。所以,不要把关键数据的保存放在onDestroy里。我习惯在onStop里做最后的保存工作,至少保证用户离开页面时数据是安全的。

@Override
protected void onDestroy() {
    super.onDestroy();
    // 清理资源
    if (mMediaPlayer != null) {
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
    // 取消异步任务
    if (mCompositeDisposable != null) {
        mCompositeDisposable.clear();
    }
}

三、生命周期组合拳:常见场景分析

场景 回调顺序 说明
首次启动Activity onCreate → onStart → onResume 标准启动流程
按Home键回到桌面 onPause → onStop Activity进入后台
从桌面返回App onRestart → onStart → onResume 注意有onRestart
按返回键退出 onPause → onStop → onDestroy 完整销毁流程
旋转屏幕(未配置configChanges) onPause → onStop → onDestroy → onCreate → onStart → onResume Activity重建
来电(非全屏弹窗) onPause → onResume 只暂停,不停止

你看,不同的场景下,生命周期的调用顺序是不一样的。我个人建议你写一个Demo,在每个回调里打Log,然后各种操作都试一遍——按Home键、旋转屏幕、接电话、启动新Activity……亲眼看到Log输出,比背十遍都管用。

四、实战中的“潜规则”

说几个我踩过的坑,希望能帮你少走弯路:

  1. onSaveInstanceState 不是生命周期方法,但它和onPause、onStop配合使用。系统会在Activity可能被销毁前调用它,让你保存临时状态。注意,它只在“非用户主动销毁”时调用——比如旋转屏幕、系统回收内存。用户按返回键时不会调用。
  2. onRestart 容易被忽略。当Activity从不可见变为可见时,如果之前已经onStop过,会先走onRestart再走onStart。我习惯在onRestart里做一些“恢复现场”的工作,比如重新加载列表数据。
  3. Fragment的生命周期比Activity更复杂。但核心逻辑是一样的——onCreate、onStart、onResume、onPause、onStop、onDestroy。只是多了onCreateView、onViewCreated等与视图相关的方法。

我的小技巧:写一个BaseActivity,把常用的生命周期逻辑封装好。比如在onPause里统一取消网络请求,在onResume里统一注册广播。这样所有子类都不用重复写这些代码了。我现在的项目里,BaseActivity大概有200行,全是生命周期相关的“防御性代码”。

五、总结:记住这三句话

好了,说了这么多,其实核心就三句话:

  • onCreate做初始化,onDestroy做清理——这是“一生一次”的配对
  • onResume开始工作,onPause暂停工作——这是“前台后台”的切换
  • onStart准备登场,onStop退居幕后——这是“可见不可见”的分界

把这六兄弟的关系理清楚,你的Activity代码至少能少一半的bug。下次写代码时,多问自己一句:“这个操作放在哪个生命周期里最合适?”久而久之,你也会形成自己的“生命周期直觉”。

嗯,今天就聊到这儿。记住,生命周期不是背出来的,是用出来的。打开你的IDE,写个Demo跑一遍,比看十篇文章都管用。


公众号:蓝海资料掘金营,微信deep3321