Android?Flutter中異常處理的方法總結(jié)
Flutter如何捕獲異常
程序異常會怎樣
- 在Java中,程序發(fā)生異常且沒有被捕獲,那么程序?qū)K止。
- 但在Dart或JavaScript中則不會,究其原因,這和它們的運(yùn)行機(jī)制有關(guān)系,Java是多線程模型的編程語言,任意一個線程觸發(fā)異常且沒被捕獲時,整個進(jìn)程就退出。
- 但Dart和JavaScript不會,它們都是單線程模型,運(yùn)行機(jī)制很相似(但有區(qū)別)。
flutter如何捕獲異常
Dart中可以通過try/catch/finally
來捕獲代碼塊異常,這個和其它編程語言類似。
Flutter框架異常捕獲
Flutter 框架在很多關(guān)鍵的方法進(jìn)行了異常捕獲。
舉一個例子,當(dāng)布局發(fā)生越界或不合規(guī)范時,F(xiàn)lutter就會自動彈出一個錯誤界面,這是因?yàn)镕lutter已經(jīng)在執(zhí)行build方法時添加了異常捕獲。
最終的源碼如下,具體看 ComponentElement 類中的 performRebuild() 方法。
@override void performRebuild() { try { //執(zhí)行build方法 built = build(); } catch (e, stack) { // 有異常時則彈出錯誤提示 built = ErrorWidget.builder(_debugReportException('building $this', e, stack)); } }
可以看到,在發(fā)生異常時,F(xiàn)lutter默認(rèn)的處理方式是彈一個ErrorWidget
但如果想自己捕獲異常并上報到報警平臺的話應(yīng)該怎么做?進(jìn)入_debugReportException()
方法看看:
FlutterErrorDetails _debugReportException( String context, dynamic exception, StackTrace stack, { InformationCollector informationCollector }) { //構(gòu)建錯誤詳情對象 final FlutterErrorDetails details = FlutterErrorDetails( exception: exception, stack: stack, library: 'widgets library', context: context, informationCollector: informationCollector, ); //報告錯誤 FlutterError.reportError(details); return details; }
發(fā)現(xiàn),錯誤是通過FlutterError.reportError
方法上報的,繼續(xù)跟蹤:
static void reportError(FlutterErrorDetails details) { ... if (onError != null) onError(details); //調(diào)用了onError回調(diào) }
發(fā)現(xiàn)onError
是FlutterError
的一個靜態(tài)屬性,它有一個默認(rèn)的處理方法 dumpErrorToConsole
,到這里就清晰了,如果想自己上報異常,只需要提供一個自定義的錯誤處理回調(diào)即可,如:
void main() { FlutterError.onError = (FlutterErrorDetails details) { reportError(details); }; ... }
這樣就可以處理那些Flutter為我們捕獲的異常了,接下來看看如何捕獲其它異常。
其它異常捕獲與日志收集
在Flutter中,還有一些Flutter沒有為我們捕獲的異常,如調(diào)用空對象方法異常、Future中的異常。
在Dart中,異常分兩類:同步異常和異步異常,同步異??梢酝ㄟ^try/catch
捕獲,而異步異常則比較麻煩,如下面的代碼是捕獲不了Future
的異常的:
try{ Future.delayed(Duration(seconds: 1)).then((e) => Future.error("xxx")); }catch (e){ print(e) }
Dart中有一個runZoned(...)
方法,可以給執(zhí)行對象指定一個Zone。
- Zone表示一個代碼執(zhí)行的環(huán)境范圍,為了方便理解,可以將Zone類比為一個代碼執(zhí)行沙箱,不同沙箱的之間是隔離的,沙箱可以捕獲、攔截或修改一些代碼行為。
- 如Zone中可以捕獲日志輸出、Timer創(chuàng)建、微任務(wù)調(diào)度的行為,同時Zone也可以捕獲所有未處理的異常。
- 下面看看
runZoned(...)
方法定義:
R runZoned<R>(R body(), { Map zoneValues, ZoneSpecification zoneSpecification, Function onError, })
zoneValues: Zone 的私有數(shù)據(jù),可以通過實(shí)例zone[key]
獲取,可以理解為每個“沙箱”的私有數(shù)據(jù)。
zoneSpecification:Zone的一些配置,可以自定義一些代碼行為,比如攔截日志輸出行為等,舉個例子:
下面是攔截應(yīng)用中所有調(diào)用print
輸出日志的行為。
main() { runZoned(() => runApp(MyApp()), zoneSpecification: new ZoneSpecification( print: (Zone self, ZoneDelegate parent, Zone zone, String line) { parent.print(zone, "Intercepted: $line"); }), ); }
這樣一來,APP中所有調(diào)用print
方法輸出日志的行為都會被攔截,通過這種方式,也可以在應(yīng)用中記錄日志,等到應(yīng)用觸發(fā)未捕獲的異常時,將異常信息和日志統(tǒng)一上報。ZoneSpecification還可以自定義一些其他行為,讀者可以查看API文檔。
onError:Zone中未捕獲異常處理回調(diào),如果開發(fā)者提供了onError回調(diào)或者通過ZoneSpecification.handleUncaughtError
指定了錯誤處理回調(diào),那么這個zone將會變成一個error-zone,該error-zone中發(fā)生未捕獲異常(無論同步還是異步)時都會調(diào)用開發(fā)者提供的回調(diào),如:
runZoned(() { runApp(MyApp()); }, onError: (Object obj, StackTrace stack) { var details=makeDetails(obj,stack); reportError(details); });
結(jié)合上面的FlutterError.onError
就可以捕獲我們Flutter應(yīng)用中全部錯誤了!需要注意的是,error-zone內(nèi)部發(fā)生的錯誤是不會跨越當(dāng)前error-zone的邊界的,如果想跨越error-zone邊界去捕獲異常,可以通過共同的“源”zone來捕獲,如:
var future = new Future.value(499); runZoned(() { var future2 = future.then((_) { throw "error in first error-zone"; }); runZoned(() { var future3 = future2.catchError((e) { print("Never reached!"); }); }, onError: (e) { print("unused error handler"); }); }, onError: (e) { print("catches error of first error-zone."); });
總結(jié)
最終異常捕獲和上報代碼如下:
void collectLog(String line){ ... //收集日志 } void reportErrorAndLog(FlutterErrorDetails details){ ... //上報錯誤和日志邏輯 } FlutterErrorDetails makeDetails(Object obj, StackTrace stack){ ...// 構(gòu)建錯誤信息 } void main() { FlutterError.onError = (FlutterErrorDetails details) { reportErrorAndLog(details); }; runZoned( () => runApp(MyApp()), zoneSpecification: ZoneSpecification( print: (Zone self, ZoneDelegate parent, Zone zone, String line) { collectLog(line); // 收集日志 }, ), onError: (Object obj, StackTrace stack) { var details = makeDetails(obj, stack); reportErrorAndLog(details); }, ); }
到此這篇關(guān)于Android Flutter中異常處理的方法總結(jié)的文章就介紹到這了,更多相關(guān)Android Flutter異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PowerManagerService之喚醒鎖的使用獲取創(chuàng)建示例解析
這篇文章主要為大家介紹了PowerManagerService之喚醒鎖的使用獲取創(chuàng)建示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Android Drawerlayout側(cè)拉欄事件傳遞問題的解決方法
這篇文章主要為大家詳細(xì)介紹了Android Drawerlayout側(cè)拉欄事件傳遞問題的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11Android編程實(shí)現(xiàn)3D滑動旋轉(zhuǎn)效果的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)3D滑動旋轉(zhuǎn)效果的方法,主要通過繼承Animation自定義Rotate3D來實(shí)現(xiàn)3D翻頁效果,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11詳解android studio游戲搖桿開發(fā)教程,仿王者榮耀搖桿
這篇文章主要介紹了android studio游戲搖桿開發(fā)教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05ViewPager實(shí)現(xiàn)輪播圖引導(dǎo)頁
這篇文章主要為大家詳細(xì)介紹了ViewPager實(shí)現(xiàn)輪播圖引導(dǎo)頁,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-09-09Android中模仿抖音加載框之兩顆小球轉(zhuǎn)動效果
這篇文章主要介紹了Android仿抖音加載框之兩顆小球轉(zhuǎn)動控件,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09