跳至内容
返回

声明式 UI 架构下的生命周期演进:从内建属性到显式订阅

发布于:  at  08:01 上午

消失的“实体”: 从View到Composable/Widget

在原生Android开发的世界, 创建模版项目后就会得到一个MainActivity和activity_main.xml. 我们习惯了在MainActivity里去绑定ButtonText再设置各种属性. 他们都是内存中看得见,摸得着的View. 但是到了Flutter中, 得到的了却是main()函数和一堆StatelessWidgetStatefulWidget. 不仅仅是Flutter, 连Jetpack Compose也在向这种’声明式UI’靠拢. Compose中同样找不到onResume(入口Activity除外),取而代之的而是层层嵌套的Composable函数

这种转变本质上是:我们不再持有 UI 的“句柄”,我们只持有“数据”。

正因为我们持有的只是数据,而数据本身是没有‘前后台’概念的(一个 String 字符串哪里知道自己是否在前台?)。所以,在声明式 UI 中寻找 onResume 本身就是一个伪命题。 只有当数据需要根据系统状态(如用户回来了)进行刷新时,我们才去主动询问系统。

生命周期演进图

onResume 不再属于 UI 组件

View体系的“重形约束”

在原生 Android 中,Activity 是一个重型容器,它直接占据着系统的窗口资源和输入焦点。这种设计决定了开发者必须拥有极强的“生存意识”:

声明式 UI 的“逻辑重构”

但在 Flutter 和 Compose 的世界里,这种“资源焦虑”被屏蔽了。我们面对的是轻量级的函数和配置。

消失的本质:为什么它们敢“干掉” onResume?

在原生 Android 中,View 是一个具有**稳定身份(Stable Identity)**的对象。你通过 findViewById 拿到的 Button,在它被销毁前,其内存地址是不变的,因此它可以安全地持有状态与生命周期回调。

而在 Flutter 中,Widget 仅是不可变的配置描述(Immutable Configuration)。 它在每一帧都可能被重新创建。 你无法给一个“瞬时快照”绑定生命周期,因为这个对象本身随时会消失。 真正具有生命周期的不是 Widget,而是底层的 State 对象,因为它在 Widget 重建时依然保持稳定。

只有当业务需要时,才去“订阅”环境

其实 Flutter 并非没有生命周期,只是它不再作为 UI 组件的内建能力。 我们需要区分三个维度的生命周期:

将这些信号与 UI 描述彻底解耦,正是 Flutter 极致灵活的原因。

Flutter 方案:监听 AppLifecycleState

在 Flutter 中,需要通过 WidgetsBindingObserver 来扮演那个“哨兵”的角色。

WidgetsBindingObserver 的订阅是 State 级别的,而不是 Widget 级别的。

// 建议替换原本的 Flutter 代码块
class MyState extends State<MyWidget> with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    // 严谨判断:只有 App 回到前台,且当前页面正处于栈顶可见时,才触发逻辑
    if (state == AppLifecycleState.resumed && ModalRoute.of(context)?.isCurrent == true) {
      _refreshData();
    }
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

Compose 方案:通过副作用显式接入宿主生命周期

Compose 并没有“移除” onResume,而是拒绝让 UI 组件隐式地持有它。

@Composable
fun OnResumeEffect(onResume: () -> Unit) {
    val lifecycleOwner = LocalLifecycleOwner.current
    LaunchedEffect(lifecycleOwner) {
        lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
            onResume()
        }
    }
}

结语:从“被动接受”到“主动订阅”

从原生 Android 转向 Flutter 或 Compose,最难的不是学习新的语法,而是思维权力的移交

在传统的 View 体系中,生命周期是系统强行塞给我们的“全家桶”,我们作为开发者,更多是在被动地接受 Activity 的调度。而声明式 UI 的出现,将组件彻底从繁重的系统环境依赖中解放出来。

这种“消亡”实际上是一种进化

生命周期没有消失,只是从“隐式回调”进化为了“显式订阅”。


在以下平台分享此文章: