【我的安卓第一课】Activity 生命周期下的重要函数 finish/onBackPressed

196 阅读4分钟

引言

Activity 生命周期是 Android 开发中的核心概念。一个 Activity 从创建到销毁会经历一系列状态,系统会在特定时刻调用相应的生命周期回调方法(如 onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy())。

深入理解并合理利用这些生命周期函数,能够帮助开发者在正确的时间执行初始化、资源管理、数据保存和释放等操作,从而开发出性能更优、用户体验更佳、稳定性更高的 Android 应用。掌握 Activity 生命周期,是迈向合格 Android 开发者的第一步。

除了生命周期方法,Android 还有一个与其息息相关的重要函数 finish()

finish()

image.png

在 Android Activity 的使用中,Activity栈非常重要,它记录着用户访问页面的历史。每当通过 Intent 启动一个新的 Activity,它就会被压入栈顶,成为当前可见的界面,这个过程中会触发onCreate, onStart, onResume。而当用户按下返回键,栈顶 Activity 可以逐个弹出,回到之前的页面,这个过程可能触发onPause, onStoponDestroy

但有时,我们可能希望通过编程的方式,主动弹出栈顶 Activity,摆脱物理操控的限制。这时就有了一个重要的方法finish()

finish()Activity 类中的一个方法,它的作用是请求系统结束当前的 Activity。调用 finish() 并不会立即销毁 Activity。它更像是在发送请求结束信号。系统收到这个信号后,会将对应 Activity 出栈,并开始执行 Activity 的销毁流程,依次调用,onPause(), onStop()onDestroy()

应用场景

  1. 主动返回 这是最常见的用法。当你在一个页面(如设置页)完成操作后,希望关闭它并返回到上一个页面。

    // 在“保存”按钮的点击事件中
    saveButton.setOnClickListener(v -> {
        saveSettings(); // 保存设置
        finish(); // 关闭当前设置页,返回上一页面 // onBackPressed
    });
    
  2. 启动新页面前并关闭当前页面 有时我们不希望用户通过返回键回到当前页面(例如登录成功后,开屏页)。

    // 登录成功后
    loginButton.setOnClickListener(v -> {
        if (loginSuccess) {
            Intent intent = new Intent(LoginActivity.this, MainActivity.class);
            startActivity(intent);
            finish(); // 关闭登录页,这样用户无法通过返回键回到登录页
        }
    });
    

相似方法 onBackPressed

实际上,相比于finish(),Android 还提供了另一个方法实现 Activity 的编码关闭 onBackPressed

onBackPressed 行为如同字义,它会完美地模拟用户按下物理返回键的所有效果。该方法最终依然是调用finish() 来实现效果。不过除了关闭当前Activity,还会有副作用

  1. 如果存在 Fragment,则优先处理 Fragment 返回栈,(本质上该方法就是点击安卓返回键)
  2. 重写点击原生返回按键时的效果
  3. 触发 onKeyDownonKeyUp (仅限点击原生返回键)

简单例子

启动新页面后删除旧页面

nofinish.giffinish.gif
不使用finish使用finish
button.setOnClickListener(v -> {
    startActivity(new Intent(this,MainActivity2.class));
    finish();  // 使用finish实现进入下一activity同时,移除当前activity
});

点击两次才执行返回

finish()也可实现类似效果,但不作用于物理返回键,同时为了语义化,通常用onBackPressed()

@Override
public void onBackPressed() {
    // 如果是第一次按下返回键
    if (!mIsBackPressedOnce) {
        mIsBackPressedOnce = true;
        Toast.makeText(this, "再按一次返回键退出", Toast.LENGTH_SHORT).show();

        // 2秒后重置状态
        mHandler.postDelayed(() -> mIsBackPressedOnce = false, 2000);
    } else {
        // 第二次按下返回键,执行默认的返回操作
        super.onBackPressed();
    }
}

或者

getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
    @Override
    public void handleOnBackPressed() {
        if (!mIsBackPressedOnce) {
            mIsBackPressedOnce = true;
            Toast.makeText(MainActivity.this, "再按一次返回键退出", Toast.LENGTH_SHORT).show();

            // 2秒后重置状态
            mHandler.postDelayed(() -> mIsBackPressedOnce = false, 2000);
        } else {
            // 第二次按下返回键,执行默认的返回操作
            getOnBackPressedDispatcher().onBackPressed();
        }
    }
});

跳过Fragment栈直接关闭

finish_fre.gifonback_fre.gif
使用finish使用onBackPress

小结

一般情况下,finish()onBackPressed() 的作用并没有非常明显的区别,以下是两者的对比。

finish()onBackPressed()
核心语义“程序逻辑要求结束”“模拟用户返回操作”
行为直接、强制结束遵循标准的返回流程
Fragment 返回栈无视,直接关闭 Activity先处理 Fragment 栈
调用后触发的行为仅执行 Activity 销毁相关逻辑除了调用 finish(),还会触发按键事件回调
推荐使用场景业务流程完成后的关闭(前进式关闭)响应用户“后退”意图(后退式关闭)

除了Fragment 返回栈问题与按键事件回调问题。一般遵循语义化原则。也即finish代表acitivty结束,onBackPressed代表点击返回键