Flutter 异常处理之图片篇
背景
說(shuō)到異常處理,你可能直接會(huì)認(rèn)為不就是 try-catch 的事情,至于寫一篇文章單獨(dú)來(lái)說(shuō)明嗎?
如果你是這么想的,那么本篇說(shuō)不定會(huì)給你驚喜哦~
而且本篇聚焦在圖片的異常處理。
場(chǎng)景
學(xué)以致用,有具體的應(yīng)用場(chǎng)景,能夠加深我們對(duì)知識(shí)的掌握。
我們以簡(jiǎn)書的文章列表為例,如下圖:
假設(shè)產(chǎn)品有這樣的需求,當(dāng)右邊的封面圖加載失敗的時(shí)候,用一個(gè)默認(rèn)圖片替換或者直接讓文本橫向填充原有圖片位置。
不管處理方式是怎樣,首先我們要做的就是能夠知道圖片加載失敗。
如何獲知圖片加載失敗呢?下面我們通過(guò) Flutter 自帶網(wǎng)絡(luò)加載 API 和一個(gè)第三方網(wǎng)絡(luò)庫(kù)來(lái)進(jìn)行對(duì)比說(shuō)明。
Image.network
我們看下源碼,如下:
Image.network(String src, {Key key,double scale = 1.0,this.semanticLabel,this.excludeFromSemantics = false,this.width,this.height,this.color,this.colorBlendMode,this.fit,this.alignment = Alignment.center,this.repeat = ImageRepeat.noRepeat,this.centerSlice,this.matchTextDirection = false,this.gaplessPlayback = false,this.filterQuality = FilterQuality.low,Map<String, String> headers,}) : image = NetworkImage(src, scale: scale, headers: headers),assert(alignment != null),assert(repeat != null),assert(matchTextDirection != null),super(key: key);可以看到只有 src 是必填參數(shù),因此我們給出 src 為不同值的情況。
1.一個(gè)圖片的 url
Widget _buildWidget() {return Image.network('https://upload-images.jianshu.io/upload_images/5361063-e413832da0038304.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/800');}能夠正常顯示如下圖:
2.不可訪問 url,如隨便一個(gè)字符串 test
Widget _buildWidget() {return Image.network('test');}終端報(bào)錯(cuò)如下:
flutter: ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════ flutter: The following ArgumentError was thrown resolving an image codec: flutter: Invalid argument(s): No host specified in URI file:///test模擬器顯示空白。
這種場(chǎng)景假設(shè)我們要捕獲異常,增加 try-catch,如下:
Widget _buildWidget() {try {return Image.network('test');} catch (e) {print('enter catch exception start');print(e);print('enter catch exception end');return Container();}}依然沒法捕獲
3.可訪問非圖片 url,比如 http://mp.weixin.qq.com/mp/homepage?__biz=MzI3OTAyNzAwNg==&hid=5&sn=7e4598d8b00537fe2846f2e85d746b9a&scene=18#wechat_redirect
Widget _buildWidget() {try {return Image.network('http://mp.weixin.qq.com/mp/homepage?__biz=MzI3OTAyNzAwNg==&hid=5&sn=7e4598d8b00537fe2846f2e85d746b9a&scene=18#wechat_redirect');} catch (e) {print('enter catch exception start');print(e);print('enter catch exception end');return Container();}}控制臺(tái)拋出如下異常
[VERBOSE-2:codec.cc(97)] Failed decoding image. Data is either invalid, or it is encoded using an unsupported format. flutter: ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════ flutter: The following _Exception was thrown resolving an image codec: flutter: Exception: operation failed可以看到 try-catch 一樣沒法生效。沒有打印相關(guān)日志。
cached_network_image
這是一個(gè)第三方開發(fā)的網(wǎng)絡(luò)庫(kù),pub 地址為 https://pub.dartlang.org/packages/cached_network_image
因?yàn)轫?xiàng)目有用到這個(gè)庫(kù),所以用這個(gè)來(lái)舉例,并不是為其打廣告,至于你實(shí)際開發(fā)是否用這個(gè)庫(kù),還是有其他更好的庫(kù),需要你自己去評(píng)估。
因?yàn)檫@個(gè)是項(xiàng)目組 iOS 同事選擇的,我這邊并沒有深入研究過(guò)。
我們仿照上面的依次執(zhí)行 3 種 case。
1.一個(gè)圖片的 url
Widget _buildWidget() {return Image(image: new CachedNetworkImageProvider('https://upload-images.jianshu.io/upload_images/5361063-e413832da0038304.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/800'));}能夠正常顯示如下圖:
2.不可訪問 url,如隨便一個(gè)字符串 test
Widget _buildWidget() {return Image(image: new CachedNetworkImageProvider('test'));}終端報(bào)錯(cuò)如下:
flutter: ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════ flutter: The following message was thrown resolving an image codec: flutter: Couldn't download or retrieve file.模擬器顯示空白。
這種場(chǎng)景假設(shè)我們要捕獲異常,增加 try-catch,如下:
Widget _buildWidget() {try {return Image(image: new CachedNetworkImageProvider('test'));} catch (e) {print('enter catch exception start');print(e);print('enter catch exception end');return Container();}}依然沒法捕獲。
但是我們通過(guò)其自帶的錯(cuò)誤回調(diào),如下:
Widget _buildWidget() {return Image(image: new CachedNetworkImageProvider('test',errorListener: () {print('enter errorListener');}));}可以看到控制臺(tái)進(jìn)入了 errorListener,打印了對(duì)應(yīng)日志。
雖然 Flutter 自帶的錯(cuò)誤日志依然輸出了,但是通過(guò) errorListener 我們可以獲得這種異常情況。
flutter: enter errorListener flutter: ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════ flutter: The following message was thrown resolving an image codec: flutter: Couldn't download or retrieve file.3.可訪問非圖片 url,比如 http://mp.weixin.qq.com/mp/homepage?__biz=MzI3OTAyNzAwNg==&hid=5&sn=7e4598d8b00537fe2846f2e85d746b9a&scene=18#wechat_redirect
Widget _buildWidget() {return Image(image: new CachedNetworkImageProvider('http://mp.weixin.qq.com/mp/homepage?__biz=MzI3OTAyNzAwNg==&hid=5&sn=7e4598d8b00537fe2846f2e85d746b9a&scene=18#wechat_redirect',errorListener: () {print('enter errorListener');}));}運(yùn)行,控制臺(tái)會(huì)報(bào)錯(cuò),并且沒法捕獲,控制臺(tái)輸出如下:
[VERBOSE-2:codec.cc(97)] Failed decoding image. Data is either invalid, or it is encoded using an unsupported format. flutter: ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════ flutter: The following _Exception was thrown resolving an image codec: flutter: Exception: operation failed使用 try-catch 也是一樣,這里就不贅余了。
圖片通用異常捕獲處理
通過(guò)上面的學(xué)習(xí),我們可以發(fā)現(xiàn)不管是 Image.network 還是 cached_network_image 沒法覆蓋全上面兩種異常的捕獲處理。
不過(guò)這兩個(gè)的共同點(diǎn)就是他們都返回 Image。
所以對(duì)于圖片的異常捕獲可以使用下面通用模板:
// Image image = Image(image: new CachedNetworkImageProvider('')); Image image = Image.network(''); final ImageStream stream = image.image.resolve(ImageConfiguration.empty); stream.addListener((_, __) {}, onError: (dynamic exception, StackTrace stackTrace) {//TODO error callback });這里首先是獲得 Image,如果獲得的是 ImageProvider,只需要把 image.image 換為你的 ImageProvider 即可,當(dāng)然這個(gè)筆者沒測(cè)試,只是看源碼上面模板 image.image 的類型是 ImageProvider。
addListener 有兩個(gè)回調(diào),其中成功回調(diào)是必填的,有兩個(gè)參數(shù),因?yàn)檫@里不需要用到,因此第一個(gè)參數(shù)是一個(gè)下劃線,第二個(gè)參數(shù)是兩個(gè)下劃線。可能你會(huì)說(shuō)不需要用到,可不可以直接填 null。不行,這邊測(cè)試了,填 null 當(dāng)圖片加載成功時(shí)控制臺(tái)會(huì)拋異常。所以提供一個(gè)不需要任何實(shí)現(xiàn)的回調(diào)即可。
錯(cuò)誤回調(diào)是可選的,因?yàn)槲覀儽酒闹黝}就是要獲取錯(cuò)誤回調(diào),所以這里提供了實(shí)現(xiàn)。
針對(duì)我們上面的 3 個(gè)例子,我們看看通用模板是否可以全部捕獲。
1.一個(gè)圖片的 url
Widget _buildWidget() {Image image = Image.network('https://upload-images.jianshu.io/upload_images/5361063-e413832da0038304.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/800');final ImageStream stream = image.image.resolve(ImageConfiguration.empty);stream.addListener((_,__){}, onError: (dynamic exception, StackTrace stackTrace) {print('enter onError start');print(exception);print(stackTrace);print('enter onError end');});return image; }圖片加載成功。
2.不可訪問 url,如隨便一個(gè)字符串 test
Widget _buildWidget() {Image image = Image.network('test');final ImageStream stream = image.image.resolve(ImageConfiguration.empty);stream.addListener((_,__){}, onError: (dynamic exception, StackTrace stackTrace) {print('enter onError start');print(exception);print(stackTrace);print('enter onError end');});return image; }控制臺(tái)輸出如下:
flutter: enter onError start flutter: Invalid argument(s): No host specified in URI file:///test flutter: #0 _HttpClient._openUrl (dart:_http/http_impl.dart:2121:9) #1 _HttpClient.getUrl (dart:_http/http_impl.dart:2056:48) #2 NetworkImage._loadAsync (package:flutter/src/painting/image_provider.dart:486:57) <asynchronous suspension> #3 NetworkImage.load (package:flutter/src/painting/image_provider.dart:471:14) #4 ImageProvider.resolve.<anonymous closure>.<anonymous closure> (package:flutter/src/painting/image_provider.dart:267:86) #5 ImageCache.putIfAbsent (package:flutter/src/painting/image_cache.dart:143:20) #6 ImageProvider.resolve.<anonymous closure> (package:flutter/src/painting/image_provider.dart:267:63) #7 SynchronousFuture.then (package:flutter/src/foundation/synchronous_future.dart:38:29) #8 ImageProvider.resolve (package:flutter/src/painting/image_provider.dart:265:30) #9 MyApp._buildWidget (package:my_flutter/main.dart:20:42) #10 MyApp.build (package:my_flutter/main.dart:12:18) #11 StatelessElement.build (package:flutter/<…> flutter: enter onError end可以看到確實(shí)進(jìn)入錯(cuò)誤回調(diào)了。
3.可訪問非圖片 url,比如 http://mp.weixin.qq.com/mp/homepage?__biz=MzI3OTAyNzAwNg==&hid=5&sn=7e4598d8b00537fe2846f2e85d746b9a&scene=18#wechat_redirect
Widget _buildWidget() {Image image = Image.network('http://mp.weixin.qq.com/mp/homepage?__biz=MzI3OTAyNzAwNg==&hid=5&sn=7e4598d8b00537fe2846f2e85d746b9a&scene=18#wechat_redirect');final ImageStream stream = image.image.resolve(ImageConfiguration.empty);stream.addListener((_,__){}, onError: (dynamic exception, StackTrace stackTrace) {print('enter onError start');print(exception);print(stackTrace);print('enter onError end');});return image; }控制臺(tái)輸出如下:
[VERBOSE-2:codec.cc(97)] Failed decoding image. Data is either invalid, or it is encoded using an unsupported format. flutter: enter onError start flutter: Exception: operation failed flutter: #0 NetworkImage._loadAsync (package:flutter/src/painting/image_provider.dart:498:12) <asynchronous suspension> #1 NetworkImage.load (package:flutter/src/painting/image_provider.dart:471:14) #2 ImageProvider.resolve.<anonymous closure>.<anonymous closure> (package:flutter/src/painting/image_provider.dart:267:86) #3 ImageCache.putIfAbsent (package:flutter/src/painting/image_cache.dart:143:20) #4 ImageProvider.resolve.<anonymous closure> (package:flutter/src/painting/image_provider.dart:267:63) #5 SynchronousFuture.then (package:flutter/src/foundation/synchronous_future.dart:38:29) #6 ImageProvider.resolve (package:flutter/src/painting/image_provider.dart:265:30) #7 MyApp._buildWidget (package:my_flutter/main.dart:20:42) #8 MyApp.build (package:my_flutter/main.dart:12:18) #9 StatelessElement.build (package:flutter/src/widgets/framework.dart:3774:28) #10 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15<…> flutter: enter onError end可以看到確實(shí)進(jìn)入錯(cuò)誤回調(diào)了。
更多閱讀:
Flutter 入門系列博客
Flutter & Dart
最后來(lái)一個(gè)彩蛋表情包:
轉(zhuǎn)載于:https://www.cnblogs.com/nesger/p/10709079.html
總結(jié)
以上是生活随笔為你收集整理的Flutter 异常处理之图片篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pycharm 进行远程服务器修改与调试
- 下一篇: 树上分块初步