自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何讓 Flutter 應(yīng)用更好地使用 SVG?

開發(fā) 開發(fā)工具
本文將帶大家了解 SVG 在 Flutter 應(yīng)用中的性能問題,分享 UC 瀏覽器內(nèi)核技術(shù)團(tuán)隊在 Flutter 應(yīng)用中改進(jìn) SVG 應(yīng)用的探索實(shí)踐。

SVG 作為一個強(qiáng)大的矢量圖標(biāo)準(zhǔn)格式,在圖片清晰度的表現(xiàn)力上有著位圖無法比擬的優(yōu)勢。那么是否 SVG 就是絕對的首選了呢?事實(shí)可能并非如此。本文將帶大家了解 SVG 在 Flutter 應(yīng)用中的性能問題,分享 UC 瀏覽器內(nèi)核技術(shù)團(tuán)隊在 Flutter 應(yīng)用中改進(jìn) SVG 應(yīng)用的探索實(shí)踐。

例說歷史

在計算機(jī)的世界里,很多空間優(yōu)化都隱藏著計算消耗,比如下面這張色彩和形狀豐富的 4k 圖片(其實(shí)也可以是 8k,屏幕夠大就可以看到),壓縮后只有 5kB 大小。[[332770]][[332771]]

??

??

 

 

如果這個 5kB 用 PNG 來存儲的圖片,是下圖這個樣子。

??

??

表現(xiàn)力天差地別。

為了達(dá)到類似的清晰度,一般操作系統(tǒng)會協(xié)助應(yīng)用打包時在 UI 資源中歸集多個分辨率的圖片。

??

??

32x32

 

??

??

64x64


 

??

??

256x256

 

 

??

??

1024x1024

 

上面這一個圖標(biāo),資源包占用超過 120kB,其中最大的一個版本,運(yùn)行內(nèi)存占用在 4MB。

這么看來,SVG 圖片應(yīng)該是絕對首選吧?

并非如此。在給 Flutter 做 SVG 支持分析之前,開發(fā)者可能覺得各個移動系統(tǒng) API 中沒有提供是個很大缺憾。

而經(jīng)過光柵化代價數(shù)據(jù)分析后,也能理解了系統(tǒng)對盲目使用 SVG 帶來問題的擔(dān)憂。

比如還是上面這個 SVG 圖片,在驍龍 626 的手機(jī)上,F(xiàn)lutter 光柵化到 64x64 的區(qū)域需要 34ms,一個 SVG 讓應(yīng)用與 60 幀流暢度徹底無緣。實(shí)測 IPhone X 需要 8ms,只能流暢顯示兩個。

另外補(bǔ)充一點(diǎn),SVG 或者說矢量圖的應(yīng)用需求是 UI 扁平化趨勢興起后才出現(xiàn)的。在擬物化的時期,拋開光柵化速度不說,矢量圖在顯示寫實(shí)風(fēng)格的圖標(biāo)時,缺陷是無法容忍的。比如 doggy,用較激進(jìn)的追蹤矢量化后(右側(cè)),已經(jīng)數(shù)碼感十足,存儲占用也遠(yuǎn)超 PNG。

??

??

好在,扁平化的矢量圖在工程推進(jìn)時,也在有意無意回避前面說的問題,大部分都走簡約風(fēng)。所以只要避開陷阱,SVG 還是在很多場景可以做到表現(xiàn)優(yōu)秀的。

應(yīng)用現(xiàn)狀

Flutter 項目主線沒有支持

Flutter 的基礎(chǔ)組件 Skia 代碼中有 SVG 目錄,但別誤會了,Skia 只有序列化至 SVG 的功能,沒有解碼繪制 SVG 的能力。

框架開發(fā)計劃目前也沒有支持的打算:https://github.com/flutter/flutter/issues/1831

OS 也沒有支持的意向

這是可以理解的,因?yàn)辇嫶笕?Android 和 iOS 也默認(rèn)不支持:

大家的共識是,全功能的 SVG 支持工作量不小,還有性能隱患(都是拐著彎提到)。

SVG 的鍋,矢量字體方案不用背

前面 SVG 咨詢,在建議解決方案中,都提到用矢量字體解決。矢量字體:

  • 主流 OS 都自帶的支持。
  • 基本只能單色。
  • 不用依賴 xml。
  • 由于單色輸出,很多圖層繪制疊加等等不可控的性能影響要素都被排除。
  • 系統(tǒng)方便做位圖緩存管理(我們開發(fā)者工具后續(xù)可以再研究)。

雖然在 SVG 投入不少研究,也不得不承認(rèn),字體矢量圖輸出是目前很務(wù)實(shí)高效的方案。

配合工具流程改進(jìn) SVG 應(yīng)用

SVG 作為一個強(qiáng)大的矢量圖標(biāo)準(zhǔn)格式,還是可以找到合適的應(yīng)用的。比如多彩圖標(biāo),方便熱更新,生產(chǎn)工具對此格式的廣泛支持。

讓 SVG 再次偉大

在 OS 和 runtime 都拋棄 SVG 的情況下,flutter_svg 包毅然然扛起大旗,簡單快捷的給 Flutter 提供了 SVG 渲染解碼的能力,顯示出 Flutter/Dart 不俗的擴(kuò)展?jié)撃堋?/p>

flutter_svg 的使用非常簡單,提供和 flutter framework 中 image_provider 類似的接口。下面兩段代碼就是分別顯示來自 asset 和網(wǎng)絡(luò)的 SVG 圖片:

SvgPicture.asset( 
'assets/adsmall.svg',
placeholderBuilder: (BuildContext context) => Container(
child: const CircularProgressIndicator()),
),

SvgPicture.network(
'https://raw.githubusercontent.com/dnfield/flutter_svg/master/example/assets/deborah_ufw/new-camera.svg',
placeholderBuilder: (BuildContext context) => Container(
child: const CircularProgressIndicator()),
),

用工具避坑

不能對 SVG 的性能隱患坐視不理。

UC 瀏覽器內(nèi)核技術(shù)團(tuán)隊開發(fā)了一個【資源面板】工具,可以方便地連接 Flutter 應(yīng)用,實(shí)時顯示資源分配的內(nèi)存,對其中的 SVG 圖片,資源面板提供了預(yù)覽和獲取光柵化損耗的功能。

??

??

通過記錄和對比 SVG 在實(shí)際移動設(shè)備上的光柵化損耗,我們可以方便地識別出有隱患的 SVG 文件,將 SVG 的應(yīng)用安排妥當(dāng)。

??

??

通過實(shí)際 Rasterization Cost 的對比可以看到,簡約風(fēng)格的圖標(biāo),時間消耗到 16.66ms 來說在驍龍 626 上也還是可以接受的。

實(shí)現(xiàn)原理

flutter_svg

flutter_svg 是一個 dart package,提供解析來自 network、asset、memory 等 SVG 的能力。

由于解析結(jié)果并不是 ui.Image 這樣的位圖,所以 flutter_svg 并沒有和 ImageCache 協(xié)作,而是自己實(shí)現(xiàn)了一套 PictureCache , PictureCache 中緩存的是 ui.Picture ,這個類實(shí)際是 skia 引擎的 SkPicture Wrapper,二進(jìn)制方式記錄具體的 SVG 繪制指令。

ui.Picture 類占用的內(nèi)存不會很大,緩存基本上是為了避免反復(fù) parse xml。

比如 SvgPicture.asset 的構(gòu)造接口如下:

SvgPicture.asset( 
String assetName, {
Key key,
this.matchTextDirection = false,
AssetBundle bundle,
String package,
this.width,
this.height,
this.fit = BoxFit.contain,
this.alignment = Alignment.center,
this.allowDrawingOutsideViewBox = false,
this.placeholderBuilder,
Color color,
BlendMode colorBlendMode = BlendMode.srcIn,
this.semanticsLabel,
this.excludeFromSemantics = false,
}) : pictureProvider = ExactAssetPicture(
allowDrawingOutsideViewBox == true
? svgStringDecoderOutsideViewBox
: svgStringDecoder,
assetName,
bundle: bundle,
package: package,
colorFilter: _getColorFilter(color, colorBlendMode)),
super(key: key);

SvgPicture 的 _picture,由 pictureProvider 的 stream 通知更新:

void _resolveImage() { 
final PictureStream newStream = widget.pictureProvider
.resolve(createLocalPictureConfiguration(context));
assert(newStream != null);
_updateSourceStream(newStream);
}

pictureProvider 的 stream 由 來自 pictureCache 的 completer 填充 ui.Picture 。

// in PictureProvider<T>.resolve 
stream.setCompleter(
_cache.putIfAbsent(
key,
() => load(key, onError: onError),
),
);

Debug 和 Profile 模式下,通過添加配合代碼,開發(fā)者工具可以在 PictureCache 中查詢所有現(xiàn)存的 SvgPicture 。

光柵化時間獲取

光柵化的發(fā)起接口是 ui.Picutre.toImage 方法,具體的計時在 rasterizer 線程。

??

??

??

??

補(bǔ)充說明

Android VectorDrawable

Android 提供了一套 VectorDrawable 方案,是一個簡化版的 SVG , 格式和特性不完全兼容,提供轉(zhuǎn)換工具。從文檔來看,確實(shí)是擔(dān)心過度復(fù)雜的 SVG 影響性能。參考文檔:https://developer.android.com/studio/write/vector-asset-studio

單獨(dú) SVG 位圖緩存優(yōu)化

目前 Flutter 用的是一次性光柵化輸出每幀的模式,和 chromium 的 cc 按區(qū)域構(gòu)建位圖再合成不同,如果在光柵化輸出時標(biāo)記 SVG 的 Picture,緩存這部分位圖可以提升幀數(shù),代價當(dāng)然是內(nèi)存損耗。

這個功能目前純用 Dart 無法方便實(shí)現(xiàn),因?yàn)樵?dart.ui 線程中,RenderPicture 無法預(yù)見具體的光柵化分辨率。

 

責(zé)任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2018-10-11 09:40:53

前端JavaScript編程語言

2021-02-25 22:17:19

開發(fā)技術(shù)編程

2019-03-22 14:20:26

管理多云云計算

2013-05-02 14:39:11

iOS開發(fā)iOS應(yīng)用崩潰解決

2015-02-26 09:19:00

2022-09-12 23:53:53

JavaScript條件判斷開發(fā)

2020-11-24 12:07:57

阿里云serverless容器

2012-02-08 16:19:09

ibmdw

2012-02-14 12:50:13

ibmdw

2014-10-29 09:55:58

程序員代碼

2015-08-21 10:38:26

DaaS

2015-11-18 09:56:24

數(shù)據(jù)中心監(jiān)控

2021-01-28 14:53:19

PHP編碼開發(fā)

2022-05-06 15:58:44

物聯(lián)網(wǎng)社區(qū)物聯(lián)網(wǎng)應(yīng)用

2015-03-12 15:00:00

編程12條自問更好地編程

2011-07-19 09:22:20

活動目錄

2022-05-05 16:49:12

物聯(lián)網(wǎng)社區(qū)應(yīng)急

2017-10-12 15:20:57

數(shù)據(jù)中心遷移數(shù)據(jù)云端

2023-11-09 11:48:41

2012-12-20 09:46:42

應(yīng)用虛擬化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號