Flutter Exception降到萬分之幾的秘密

閒魚技術發表於2018-12-25

Flutter exception

閒魚技術團隊於2018年上半年率先引入了Flutter技術實現客戶端開發,到目前為止成功改造並上線了複雜的商品詳情和釋出業務。隨著flutter比重越來越多,我們開始大力治理flutter的exception,起初很長一段時間內閒魚內flutter的exception率一直在千分之幾左右。經過我們的整理和解決,解決了90%以上的flutter exception。

我們對exception進行了歸類,大頭主要分為兩大類,這兩大類堆疊數量很多,佔到整體90%左右:

第一大類的堆疊都指向了setstate

#0      State.setState (package:flutter/src/widgets/framework.dart:1141)
#1      _DetailCommentWidgetState.replyInput.<anonymous closure>.<anonymous closure> (package:fwn_idlefish/biz/item_detail/fx_detail_comment.dart:479)
#2      FXMtopReq.sendReq.<anonymous closure> (package:fwn_idlefish/common_lib/network/src/mtop_req.dart:32)
#3      NetService.requestWithModel.<anonymous closure> (package:fwn_idlefish/common_lib/network/src/net_service.dart:58)
#4      _rootRunUnary (dart:async/zone.dart:1132)
#5      _CustomZone.runUnary (dart:async/zone.dart:1029)
#6      _FutureListener.handleValue (dart:async/future_impl.dart:129)

第二大類堆疊都與buildContext相關

#0      Navigator.of (package:flutter/src/widgets/navigator.dart:1270)
#1      Navigator.pop (package:flutter/src/widgets/navigator.dart:1166)
#2      UploadProgressDialog.hide (package:fwn_idlefish/biz/publish/upload_progress_dialog.dart:35)
#3      PublishSubmitReducer.doPost.<anonymous closure> (package:fwn_idlefish/biz/publish/reducers/publish_submit_reducer.dart:418)
<asynchronous suspension>
#4      FXMtopReq.sendReq.<anonymous closure> (package:fwn_idlefish/common_lib/network/src/mtop_req.dart:32)
#5      NetService.requestWithModel.<anonymous closure> (package:fwn_idlefish/common_lib/network/src/net_service.dart:58)
#6      _rootRunUnary (dart:async/zone.dart:1132)
#7      _CustomZone.runUnary (dart:async/zone.dart:1029)

第一類明顯與element和sate的生命週期有關。第二類與buildContext有關。

buildContext是什麼?

下面是一段state中獲取buildContext的實現

Element get _currentElement => _registry[this];
BuildContext get currentContext => _currentElement;

很明顯buildContext其實就是element例項。buildContext是一個介面,element是buildContext的具體實現。所以上面的exception都指向了flutter element和state的生命週期。

Flutter 生命週期

state生命週期

Flutter Exception降到萬分之幾的秘密

element與state生命週期

element是由widget createElement所建立。state的生命週期狀態由element呼叫觸發。

Flutter Exception降到萬分之幾的秘密

最核心的是在new elment的時候element的state的雙向繫結正式建立。在umount的時候element和state的雙向繫結斷開。

activity生命週期與state關係

flutter提供WidgetsBindingObserver給開發者來監聽AppLifecycleState。 AppLifecycleState有4種狀態:

  1. 1.resumed

  2. 介面可見,比如應用從後臺到前臺


  3. 2.inactive

  4. 頁面退到後臺或者彈出dialog等情況下

  5. 這種狀態下接收不到很任何使用者輸入,但是還會有drawframe的回撥


  6. 3.paused

  7. 應用掛起,比如退到後臺。進入這種狀態代表不在有任何drawframe的回撥


  8. 4.suspending

  9. ios中沒用,puased之後進入的狀態,進入這種狀態代表不在有任何drawframe的回撥

看下android生命週期和appLifecycleState、state關係,

1.建立

Flutter Exception降到萬分之幾的秘密

2.按home鍵退到後臺

Flutter Exception降到萬分之幾的秘密

3.從後臺回到前臺

Flutter Exception降到萬分之幾的秘密

4.back鍵退出當前頁面(route pop)

Flutter Exception降到萬分之幾的秘密

5.back鍵退出應用

Flutter Exception降到萬分之幾的秘密常見的exception例子

工程開發中容易忽略state的dispose狀態

看一段例子:

Flutter Exception降到萬分之幾的秘密

這個例子可能會在某些情況下excetion。

在state dispose後,element會和state斷開相互引用,如果在這個時候開發者去拿element的位置資訊或者呼叫setstate 重新整理佈局時就會報異常。

最常見的是在一些timer、animate、網路請求等非同步邏輯後呼叫setstate導致的excetion。安全的做法是在呼叫setstate前判斷一下state是否是mounted狀態。如下:

Flutter Exception降到萬分之幾的秘密

buildContext使用錯誤

看一段錯誤使用buildcontext例子:

Flutter Exception降到萬分之幾的秘密

上面的錯誤在於在跨堆疊使用了buildcontext。由於outcontext的生命週期與buttomcontext不一致,在彈出bottomsheet的時候outcontext可以已經處於umount或者deactivite。上面例子正確的做法是使用bottomcontext獲取focusScopeNode。

我們在跨堆疊傳遞引數(如bottomsheet、dialog、alert、processdialog等)場景時特別要注意buildcontext的使用。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69900359/viewspace-2286381/,如需轉載,請註明出處,否則將追究法律責任。

相關文章