Flutter 中的Error的捕获及处理
前言
Flutter 框架可以捕獲運行期間的錯誤,包括構建期間、布局期間和繪制期間。
所有 Flutter 的錯誤均會被回調方法?FlutterError.onError?捕獲。默認情況下,會調用?FlutterError.dumpErrorToConsole?方法,正如方法名表示的那樣,將錯誤轉儲到當前的設備日志中。當從 IDE 運行應用時,檢查器重寫了該方法,錯誤也被發送到 IDE 的控制臺,可以在控制臺中檢查出錯的對象。
當構建期間發生錯誤時,回調函數?ErrorWidget.builder?會被調用,來生成一個新的 widget,用來代替構建失敗的 widget。默認情況,debug 模式下會顯示一個紅色背景的錯誤頁面, release 模式下會展示一個灰色背景的空白頁面。
如果在調用堆棧上沒有 Flutter 回調的情況下發生錯誤(這里可以理解為FlutterError.onError僅僅可以捕獲主線程的錯誤,而其他異步線程的錯誤則需要Zone來捕獲),它們由發生區域的?Zone?處理。?Zone?在默認情況下僅會打印錯誤,而不會執行其他任何操作。
這些回調方法都可以被重寫,通常在?void main()?方法中重寫。
下面來看看如何處理。
捕獲Flutter錯誤
重寫FlutterError的onError即可,如下:
import 'dart:io';import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart';void main() {FlutterError.onError = (FlutterErrorDetails details) {FlutterError.dumpErrorToConsole(details);if (kReleaseMode)... //處理線上錯誤,如統計上傳};runApp(MyApp()); }上面我們重寫了FlutterError.onError,這樣就可以捕獲到錯誤,第一行代碼就是將error展示到控制臺,這樣我開發時就會在控制臺很方便的看到錯誤。下面代碼就是在線上環境下,對錯誤進一步處理,比如統計上傳。
自定義ErrorWidget
上面我們知道,構建時發生錯誤會默認展示一個錯誤頁面,但是這個頁面很不友好,我們可以自定義一個錯誤頁面。定義一個自定義的 error widget,以當 builder 構建 widget 失敗時顯示,請使用 MaterialApp.builder。
class MyApp extends StatelessWidget { ...@overrideWidget build(BuildContext context) {return MaterialApp(...builder: (BuildContext context, Widget widget) {Widget error = Text('...rendering error...');if (widget is Scaffold || widget is Navigator)error = Scaffold(body: Center(child: error));ErrorWidget.builder = (FlutterErrorDetails errorDetails) => error;return widget;},);} }在App下的builder中,自定義一個error頁面,然后賦值給ErrorWidget.builder即可。這樣再出現錯誤的時候就可以展示一個友好的頁面。
無法捕獲的錯誤
假設一個 onPressed 回調調用了異步方法,例如 MethodChannel.invokeMethod (或者其他 plugin 的方法):
OutlinedButton(child: Text('Click me!'),onPressed: () async {final channel = const MethodChannel('crashy-custom-channel');await channel.invokeMethod('blah');}, ),如果 invokeMethod 拋出了錯誤,它不會傳遞至 FlutterError.onError,而是直接進入 runApp 的 Zone。
如果你想捕獲這樣的錯誤,請使用 runZonedGuarded。代碼如下:
import 'dart:async';void main() {runZonedGuarded(() {runApp(MyApp());}, (Object error, StackTrace stack) {... //處理錯誤}); }請注意,如果你的應用在 runApp 中調用了 WidgetsFlutterBinding.ensureInitialized() 方法來進行一些初始化操作(例如 Firebase.initializeApp()),則必須在 runZonedGuarded 中調用 WidgetsFlutterBinding.ensureInitialized():
runZonedGuarded(() async {WidgetsFlutterBinding.ensureInitialized();await Firebase.initializeApp();runApp(MyApp()); }如果 `WidgetsFlutterBinding.ensureInitialized()` 在外部調用,錯誤將不會被捕獲到。
完整處理流程
如果要處理上面全部問題,則先通過runZonedGuarded處理異步錯誤,再通過FlutterError.onError處理,這些錯誤都通過一個我們自定義的MyErrorsHandler類來集中處理即可,比如統計上傳等。然后在app中還需要定義一個友好的錯誤頁面。
源碼
關注公眾號:BennuCTech,發送“FlutterError”獲取完整源碼。
?
總結
以上是生活随笔為你收集整理的Flutter 中的Error的捕获及处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Flutter如何与Native(And
- 下一篇: RecyclerView局部刷新机制——