爲何有這篇文章?java
這篇文章能夠說是我的Flutter問題隨筆吧,雖然Flutter能夠方便的作到跨平臺,可是畢竟是新項目,功能沒那麼全面也是意料之中,因此在此記錄跟蹤一下目前在使用Flutter過程當中遇到的問題,目前的解決方案,並跟蹤記錄一下。android
問題列表(持續更新):git
這個源自於我的練手APP,在開發閱讀模塊過程當中遇到了這麼一個問題:github
若是想要自定義文字間距,段落間距等,那麼天然就要使用textPainter本身繪製文字。可是由此引起出一個問題:若是有上萬個文字,那麼測繪時間會很長。天然會阻塞主進程。canvas
解決這個問題,第一個想法天然就是使用異步處理,那麼flutter 中的異步方案有哪些呢?緩存
按照官方文檔,大量計算東西應該放到Isolate中,因此,天然而然地,咱們將textPinter測繪方法放到Isolate中執行,可是呢,執行報錯:native function not foundbash
緣由就是UI包的類只容許在Flutter的UI Isolate中執行。服務器
此題無解,完結撒花,各回各家,各找各媽(纔怪)異步
解決方案一:Pluginasync
這個方法的思路來自於官方開發人員的回答:
right now you would have to write your own line-breaking logic - perhaps as a plugin. We don't currently have any API for doing text layout in a separate isolate. @GaryQian might have some other idea about this too.
因此說,咱們看下官方的Plugin是怎麼實現的。
在 Plugin工程中,有這麼一個: android_alarm_manager ,這個Plugin中的AlarmService.java文件中,有這麼一個方法:startBackgroundIsolate(要素察覺+1)
經過閱讀源碼,咱們得知,其實說白了就是新建一個FlutterNativeView ,這個FlutterNativeView 不負責渲染界面,只負責當後臺線程來用。一樣的道理,咱們也能夠用一樣的方法來處理咱們的須要運行在UI Isolate的異步任務。(至於爲何新建一個FlutterNativeView ,就能實現這個需求,粗略的說下是由於,每次新建FlutterNativeView,其實都會新建一些TaskRunner,其中就包含UI 的TaskRunner,總之有興趣的能夠搜下Flutter中的TaskRunner機制瞭解下)
不過,其實不用本身實現註冊,有這麼一個第三方:flutter_isolate能夠作到這點,用法跟普通的isolate差很少,因此解決方式也很簡單:找到原來使用Isolate的那段代碼,把Isolate.spawn替換爲FlutterIsolate.spawn便可。不過通過測試,在1.10版本上會報錯,因此想使用這個方式的話,仍是切回stable 分支使用吧。
解決方案二:分割爲多個小任務(我的感受不太推薦這種方式,感受不可控,畢竟假如小任務的執行時間也很長咋辦)
這種方式說白了就是每測繪完一行,就提交一次,而不是總體測繪完以後再提交結果。
舉個小例子:
Future(() async {
var result;
for (var i = 0; i < 1000000; ++i) {
result = 'result is $i';
await Future.delayed(Duration.zero);
}
print(result);
});
複製代碼
用這種方式計算就不會卡UI
解決方案三:目前這個問題已經加入到里程碑了,在將來的某天應該就有解決方案
也就是像音樂播放器那樣,會有個通知顯示進度,即便在桌面也能夠播放音樂這種
目前只有Android的實現,IOS這塊目前尚未方案……%
找了半天才發現有個大佬已經搞定了這個問題:
使用extended_nested_scroll_view便可解決這個問題,在此記錄一下
這個描述可能有些抽象,具體狀況以一個例子爲例描述:
1、首頁放一個圖片,給他設置點擊跳轉詳情頁,並設置hero動畫。
2、將圖片設置爲SliverAppBar的FlexibleSpaceBar的widget中的內容,而後上拉頁面,摺疊隱藏掉SliverAppBar。
3、按後退鍵退出詳情頁,觸發hero的關閉動畫。
按這三步執行以後,首頁原來那張圖片就變成空白,並且沒法點擊。
issue:
因此切換到master分支或者dev分支(問題修復版本v.1.10.14),或者下降穩定版的版本。
下面是我搜索出的內容:
stackoverflow.com/questions/5…
上面的實現方法各有千秋吧,整理一下主要的缺陷點,之後能夠根據實際狀況使用:
如今正在嘗試解決ScrollablePositionedList中的視差滑動問題,(得想個辦法讓NestScrollView屆的到ScrollablePositionedList的controller) 在NestScrollView中是經過設置PrimaryScrollController,讓innerController管理body滑動的,因此使用這個innerController來替代ScrollablePositionedList的controller便可解決沒法滑動的問題,可是隨之而來的是一個新的問題,如今按index跳轉,會致使body觸發滑動,進而直接摺疊掉SliverAppBar……………如何讓index跳轉的時候,body在NestScrollView中的位置不動,只在原地實現自身的index跳轉,只有手動滑動的時候才容許改變body在NestScrollView中的位置,目前想法是在SliverAppBar的floating、pinned等控制滑動方式的方法上看看有沒有突破口。 不搞了,如今挺好的。直接滿屏展現,實在不行加個跳轉到頂部按鈕,我感受蠻合理的。(大霧)
改變高度這個,目前採用設置addPersistentFrameCallback 方式持續監聽。本覺得應該性能比較差,可是測試了一下,好像frame沒啥變化,因此應該沒啥問題。
有些同窗可能對我爲何須要測量上萬字感到困惑,因此在這簡單的提下:
測繪上萬字這個狀況來自於我想把本身原來的一個Android原生小說閱讀器,轉換爲flutter實現(主要是想實現那幫仿真、滾動等翻頁動畫啥的,練習一下flutter的canvas操做),小說閱讀器的基本思路參考自這個項目:任閱。
思路基本是這樣的:
基本功能是:上一頁,下一頁,上一章,下一章,章內跳頁。
由於要考慮上一章下一章切換以及章內跳轉到多少頁的這些功能,因此天然以章爲基礎單位,章內部包含頁,取的時候把章的數據拿出來,而後從章中頁數據中取出要展現的頁的數據,並將其繪製到canvas上。
因此,緩存計算也是計算的章的內容,因此當從服務器下載下來新的章的時候,就有可能遇到上萬字的章的狀況。
可能也有同窗說:直接按頁緩存不就好了,每次只緩存幾頁的內容,那確定不會遇到須要一次性測量上萬字的狀況。可是若是純粹按頁緩存的話,若是遇到這兩種狀況就傻眼了:1. 若是有個用戶打開一本新的小說,直接跳到第十章,而後按了上一頁。 2. 章節內跳轉到第n頁(n>緩存頁數)。
由於標點符號、全角、特殊字符等非普通漢字的存在,因此咱們是沒法直接得知每頁展現的內容,天然沒法在測量完整章以前得知某頁的展現內容,因此要支持上面提到2個狀況,必然要測量分頁整章內容。
固然,可能我這個思路也不是最優解,若是有更好的方案,但願各位不吝指教