Flutter - 生命週期監聽和管理

Sunday1990發表於2019-05-16

前言

Android開發者應該知道google出了一套管理生命週期的框架,詳細的可以移步到這裡。那在flutter中有沒有類似這種庫呢?筆者找了挺久沒找到,所以最終決定研究下Android那邊的實現原理,然後寫一個flutter的版本,具體細節做了些調整,專案地址:flib_lifecycle

如何分發

  1. 首先寫一個用於分發生命週期的State基類,如下:
abstract class LifecycleState<T extends StatefulWidget> extends State<T> implements FLifecycleOwner {
  final FLifecycleRegistry _lifecycleRegistry = SimpleLifecycleRegistry();
  
  @override
  FLifecycle getLifecycle() {
    return _lifecycleRegistry;
  }

  @override
  void initState() {
    super.initState();
    // 分發[FLifecycleEvent.onCreate]事件
    _lifecycleRegistry.handleLifecycleEvent(FLifecycleEvent.onCreate);
  }

  @override
  void dispose() {
    // 分發[FLifecycleEvent.onDestroy]事件
    _lifecycleRegistry.handleLifecycleEvent(FLifecycleEvent.onDestroy);
    super.dispose();
  }
}
複製程式碼

上面程式碼中分發事件的寫法,也可以寫為標記為某種狀態,同樣可以通知生命週期事件給觀察者

// 分發事件
_lifecycleRegistry.handleLifecycleEvent(FLifecycleEvent.XXX);

// 標記為某種狀態
_lifecycleRegistry.markState(FLifecycleState.XXX);
複製程式碼
  1. 繼承LifecycleState,如下
class _DemoPageState extends LifecycleState<DemoPage> {
  @override
  void initState() {
    super.initState();
    // 新增觀察者
    getLifecycle().addObserver(_lifecycleListener);
  }

  void _lifecycleListener(FLifecycleEvent event, FLifecycle lifecycle) {
    print('_lifecycleListener: ' +
        event.toString() +
        ' State: ' +
        lifecycle.getCurrentState().toString());
  }

  @override
  void dispose() {
    super.dispose();
    // 移除觀察者
    getLifecycle().removeObserver(_lifecycleListener);
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
    );
  }
}
複製程式碼

執行後開啟此介面,再關閉介面,控制檯日誌如下:

I/flutter (26755): _lifecycleListener: FLifecycleEvent.onCreate State: FLifecycleState.created
I/flutter (26755): _lifecycleListener: FLifecycleEvent.onDestroy State: FLifecycleState.destroyed
複製程式碼

更多的生命週期事件

在Android中,Activity還有更多的生命週期事件,比如onStart(),onResume(),onPause(),onStop()等,那flutter中的State有沒有像Android那麼詳細的生命週期事件呢?很遺憾,沒有像Android中那麼詳細,但是可以嘗試實現。

筆者覺得至少要有以下幾個狀態和生命週期:

/// 生命週期狀態
enum FLifecycleState {
  /// 銷燬狀態 
  destroyed,
  /// 初始化狀態
  initialized,
  /// 建立狀態
  created,
  /// 活動狀態
  started,
}

/// 生命週期事件
enum FLifecycleEvent {
  /// 分發此事件後處於[FLifecycleState.created]狀態
  onCreate,
  /// 分發此事件後處於[FLifecycleState.started]狀態
  onStart,
  /// 分發此事件後處於[FLifecycleState.created]狀態
  onStop,
  /// 分發此事件後處於[FLifecycleState.destroyed]狀態
  onDestroy,
}
複製程式碼

有了以上幾個狀態,才方便後續實現更多的功能,比如處於建立狀態的話就停止定時器,處於活動狀態重新開始定時器等。那flutter中的State應該如何分發onStart和onStop事件呢?筆者目前的實現方案如下:

  1. 寫一個State的生命週期分發介面卡
class FStateLifecycleAdapter implements FLifecycleOwner, _StateLifecycle {
  final FLifecycleRegistry _lifecycleRegistry;
  bool _started;
  bool _startedMarker;

  FStateLifecycleAdapter({FLifecycleRegistry lifecycleRegistry})
      : this._lifecycleRegistry = lifecycleRegistry ?? SimpleLifecycleRegistry();

  @override
  FLifecycle getLifecycle() {
    return _lifecycleRegistry;
  }

  @override
  void initState() {
    _lifecycleRegistry.handleLifecycleEvent(FLifecycleEvent.onCreate);
  }

  @override
  Widget build(BuildContext context) {
    if (_startedMarker == null) {
      _startedMarker = true;
    }

    if (_startedMarker) {
      _startedMarker = false;
      _started = true;
      _notifyStartOrStop();
    }

    return null;
  }

  @override
  void deactivate() {
    assert(_startedMarker == false);

    final bool expected = !_started;
    if (expected) {
      _startedMarker = true;
      // 等待build
    } else {
      _started = false;
      _notifyStartOrStop();
    }
  }

  @override
  void dispose() {
    _started = null;
    _startedMarker = null;
    _lifecycleRegistry.handleLifecycleEvent(FLifecycleEvent.onDestroy);
  }

  void _notifyStartOrStop() {
    if (_started == null) {
      return;
    }
    if (_started) {
      _lifecycleRegistry.handleLifecycleEvent(FLifecycleEvent.onStart);
    } else {
      _lifecycleRegistry.handleLifecycleEvent(FLifecycleEvent.onStop);
    }
  }
}

abstract class _StateLifecycle {
  void initState();

  Widget build(BuildContext context);

  void deactivate();

  void dispose();
}
複製程式碼
  1. 使用介面卡改造一下LifecycleState,程式碼如下:
abstract class LifecycleState<T extends StatefulWidget> extends State<T> implements FLifecycleOwner {
  final FStateLifecycleAdapter _stateLifecycleAdapter = FStateLifecycleAdapter();

  @override
  FLifecycle getLifecycle() {
    return _stateLifecycleAdapter.getLifecycle();
  }

  @override
  void initState() {
    super.initState();
    _stateLifecycleAdapter.initState();
  }

  @override
  void deactivate() {
    super.deactivate();
    _stateLifecycleAdapter.deactivate();
  }
  
  @override
  Widget build(BuildContext context) {
    _stateLifecycleAdapter.build(context);
    return buildImpl(context);
  }
  
  /// 由於需要佔用build方法,所以這邊重新定了一個buildImpl方法用於返回Widget。
  Widget buildImpl(BuildContext context);

  @override
  void dispose() {
    _stateLifecycleAdapter.dispose();
    super.dispose();
  }
}
複製程式碼
  1. 繼承改造後的LifecycleState
class _DemoPageState extends LifecycleState<DemoPage> {
  @override
  void initState() {
    super.initState();
    getLifecycle().addObserver(_lifecycleListener);
  }

  void _lifecycleListener(FLifecycleEvent event, FLifecycle lifecycle) {
    print('_lifecycleListener: ' +
        event.toString() +
        ' State: ' +
        lifecycle.getCurrentState().toString());
  }

  @override
  void dispose() {
    super.dispose();
    getLifecycle().removeObserver(_lifecycleListener);
  }

  @override
  Widget buildImpl(BuildContext context) {
    return Container(
      color: Colors.white,
      child: GestureDetector(
        child: Text('開啟MainPage'),
        onTap: () {
          Navigator.of(context).pushNamed('MainPage');
        },
      ),
    );
  }
}
複製程式碼

執行後按如下操作後日志如下:

  1. 開啟DemoPage
I/flutter (26755): _lifecycleListener: FLifecycleEvent.onCreate State: FLifecycleState.created
I/flutter (26755): _lifecycleListener: FLifecycleEvent.onStart State: FLifecycleState.started
複製程式碼
  1. 跳轉到MainPage
I/flutter (26755): _lifecycleListener: FLifecycleEvent.onStop State: FLifecycleState.created
複製程式碼
  1. 關閉MainPage
I/flutter (26755): _lifecycleListener: FLifecycleEvent.onStart State: FLifecycleState.started
複製程式碼
  1. 關閉DemoPage
I/flutter (26755): _lifecycleListener: FLifecycleEvent.onStop State: FLifecycleState.created
I/flutter (26755): _lifecycleListener: FLifecycleEvent.onDestroy State: FLifecycleState.destroyed
複製程式碼

後續我們就可以通過生命週期的監聽實現更多的功能, 例如Android中的LiveData,可以設定觀察者監聽值的變化,生命週期分發銷燬事件後自動釋放觀察者。

flutter版本的LiveData筆者已經寫好了,有興趣的讀者移步到這裡,後面也會專門寫一篇文章介紹怎麼使用。

結束語

文章中沒有對flutter中State原本的生命週期做過多的介紹,如果需要了解大家可以去搜尋一下,有很多相關的文章。由於筆者也是剛接觸flutter不久,還有很多需要學習的地方,如果文章中有錯誤的地方,還請讀者幫忙指正。

關於這個庫有疑問的,或者需要探討的可以和我聯絡,大家一起學習。
筆者郵箱:565061763@qq.com。

相關文章