?
前言
在上一篇文章《Flutter混合開發(fā):Android中如何啟動Flutter》中我們學(xué)習(xí)了如果在Android項目中使用Flutter,在使用過程中經(jīng)常會遇到各種錯誤,那么如何處理這些錯誤?
Flutter 框架可以捕獲運(yùn)行期間的錯誤,包括構(gòu)建期間、布局期間和繪制期間。
關(guān)于Flutter錯誤的處理包含三個部分:
- onError:處理主線程發(fā)生的錯誤
- ErrorWidget:錯誤發(fā)生時的展示頁面
- Zone:處理其他異步線程中(onError無法處理)的錯誤
下面來看看如何處理。
主線程錯誤
所有 Flutter 主線程的錯誤均會被回調(diào)方法 FlutterError.onError 捕獲。默認(rèn)情況下,會調(diào)用 FlutterError.dumpErrorToConsole 方法,正如方法名表示的那樣,將錯誤轉(zhuǎn)儲到當(dāng)前的設(shè)備日志中。當(dāng)從 IDE 運(yùn)行應(yīng)用時,檢查器重寫了該方法,錯誤也被發(fā)送到 IDE 的控制臺,可以在控制臺中檢查出錯的對象。
所以捕獲這部分錯誤只需要重寫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)
... //處理線上錯誤,如統(tǒng)計上傳
};
runApp(MyApp());
}
上面我們重寫了FlutterError.onError,這樣就可以捕獲到錯誤,第一行代碼就是將error展示到控制臺,這樣我開發(fā)時就會在控制臺很方便的看到錯誤。下面代碼就是在線上環(huán)境下,對錯誤進(jìn)一步處理,比如統(tǒng)計上傳。
默認(rèn)錯誤頁面
當(dāng)構(gòu)建期間發(fā)生錯誤時,回調(diào)函數(shù) ErrorWidget.builder 會被調(diào)用,來生成一個新的 widget,用來代替構(gòu)建失敗的 widget。默認(rèn)情況,debug 模式下會顯示一個紅色背景的錯誤頁面, release 模式下會展示一個灰色背景的空白頁面。如下:
?
上面我們知道,構(gòu)建時發(fā)生錯誤會默認(rèn)展示一個錯誤頁面,但是這個頁面很不友好,我們可以自定義一個錯誤頁面。定義一個自定義的 error widget,以當(dāng) builder 構(gòu)建 widget 失敗時顯示,請使用 MaterialApp.builder。
class MyApp extends StatelessWidget {
...
Widget 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即可。這樣再出現(xiàn)錯誤的時候就可以展示一個友好的頁面,提示用戶重啟或者升級應(yīng)用等。
異步線程錯誤
如果在調(diào)用堆棧上沒有 Flutter 回調(diào)的情況下發(fā)生錯誤(這里可以理解為FlutterError.onError僅僅可以捕獲主線程的錯誤,而其他異步線程的錯誤則需要Zone來捕獲),它們由發(fā)生區(qū)域的 Zone 處理。 Zone 在默認(rèn)情況下僅會打印錯誤,而不會執(zhí)行其他任何操作。
假設(shè)一個 onPressed 回調(diào)調(diào)用了異步方法,例如 MethodChannel.invokeMethod (或者其他 plugin 的方法):
OutlinedButton(
child: Text('Click me!'),
onPressed: () async {
final channel = const MethodChannel('crashy-custom-channel');
await channel.invokeMethod('blah');
},
),
如果 invokeMethod 拋出了錯誤,它不會傳遞至 FlutterError.onError,而是直接進(jìn)入 runApp 的 Zone。
如果你想捕獲這樣的錯誤,請使用 runZonedGuarded。代碼如下:
import 'dart:async';
void main() {
runZonedGuarded(() {
runApp(MyApp());
}, (Object error, StackTrace stack) {
... //處理錯誤
});
}
請注意,如果你的應(yīng)用在 runApp 中調(diào)用了 WidgetsFlutterBinding.ensureInitialized() 方法來進(jìn)行一些初始化操作(例如 Firebase.initializeApp()),則必須在 runZonedGuarded 中調(diào)用 WidgetsFlutterBinding.ensureInitialized():
runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
如果 WidgetsFlutterBinding.ensureInitialized() 在外部調(diào)用,錯誤將不會被捕獲到。
完整解決方案
所以flutter中完整的處理錯誤流程實際上是分三步的
- 先通過runZonedGuarded處理異步錯誤
- 再通過FlutterError.onError處理
(runZonedGuarded和onError捕獲的這些錯誤可以通過一個我們自定義的MyErrorsHandler類來集中處理即可,比如統(tǒng)計上傳等。) - 最后還需要自定義一個友好的錯誤頁面來取代默認(rèn)錯誤頁面。
完整代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-400017.html
總結(jié)
可以看到再處理Flutter中的Error的時候,我們要分情況進(jìn)行處理,主線程和異步線程的錯誤通過不同的方式進(jìn)行捕獲,但是處理可以統(tǒng)一。另外為了更友好的展示,可以重新定義一個錯誤頁面來替換默認(rèn)的錯誤頁面,這樣當(dāng)出錯的時候會顯示一個很友好的頁面來提示用戶。文章來源地址http://www.zghlxwxcb.cn/news/detail-400017.html
到了這里,關(guān)于Flutter開發(fā):Error的捕獲及處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!