在FlutterBoost下FadeInImage反復(fù)刷新問題

問題背景

路由框架采用flutterboost盾剩,根視圖UITabbarController的其中一個item的頁面是flutter呵扛,該flutter頁面采用了FadeInImage顯示圖片添吗,其余都是native讳侨。在剩余的native中可以點擊進(jìn)入flutter頁面粘拾。直接看現(xiàn)象:

2021-09-15 14.41.42.gif

結(jié)果:只要切換了別的flutter頁面再回內(nèi)嵌在TabbarItem的flutter頁面憔晒,頁面中的圖片就會重新動畫。

開始以為是自己的項目哪里沒寫對明吩,想著放到flutterboost的example上嘗試一下间学,

在tabItem頁隨便添加一個widget:

FadeInImage.assetNetwork(
  placeholder: "images/flutter.png",
  image: "https://gw.alicdn.com/tfs/TB1aUlEYLb2gK0jSZK9XXaEgFXa-252-252.png",
  width: 300,
  height: 300,
  fadeOutDuration: const Duration(milliseconds: 300),
  fadeInDuration: const Duration(milliseconds: 700),
),

現(xiàn)象如下:

2021-09-16 11.01.43.gif

結(jié)果:同樣的場景,得到了一個更讓人奇怪的現(xiàn)象印荔,切換了tab就會重新動畫菱鸥,不切tab怎么玩都沒關(guān)系。

排查過程

1.首先先查明為什么會刷新圖片躏鱼,來到FadeinImage內(nèi)部的build方法

image-20210915154239430.png

通過斷點調(diào)試最終發(fā)現(xiàn)圖片是通過imageframBuilder回調(diào)創(chuàng)建視圖,而該回調(diào)中的wasSynchronouslyLoaded決定了是返回網(wǎng)絡(luò)圖片殷绍,還是返回占位圖動畫染苛。所以再跟進(jìn)去看一下。

官方注解:如果framBuilder為null主到,一旦第一個圖像幀可用茶行,則此小部件將顯示繪制為的圖像。調(diào)用方也可以使用此生成器向圖像添加效果(例如在圖像變暗時淡入)或在加載圖像時顯示占位符小部件登钥。

2.看一下Image的build方法畔师,因為image是一個statefulwidget,所以這里是imageState

image-20210915160330391.png

也驗證了剛才的說的官方注解牧牢。那么就看一下為什么tab切換這里返回的是wasSynchronouslyLoadedfasle看锉,其他情況都是true姿锭。

3.查看Widget樹,發(fā)現(xiàn)兩種切換方式層級都是一樣的伯铣。

image-20210915165550149.png

眾所周知呻此,當(dāng)同級的子樹發(fā)生變化的時候,都用didChangeDependencies()腔寡,每次都會進(jìn)入_updateSourceStream

image-20210915172035541.png
image-20210915172256536.png

關(guān)鍵可以看到這個方法焚鲜,關(guān)鍵在于如果_imageStream.key不相等,wasSynchronouslyLoaded就設(shè)置成false了放前。如果正常加載過一次忿磅,該值默認(rèn)就是true,這個這里就不展開了凭语。這里的key是stream的completer對象葱她。

image-20210915173815574.png

4.到這就更奇怪了,為什么URL都是一樣的叽粹,_imageStream為啥會不一樣呢览效?這里主要就要看下這個newStream是怎么拼出來的了。這塊代碼會有點深虫几,說結(jié)論:

image-20210915174053453.png
image-20210915173928584.png

imageCache的_cache屬性如果有key锤灿,直接返回image.completer。所以通過斷點發(fā)現(xiàn)辆脸,切換tab但校。

到這里的結(jié)論就是這里的_cache在某個時刻清空了,導(dǎo)致返回的key(image.completer)不一致了啡氢。

5.看看_cache在何時清空的:

image-20210915180522047.png

看起來是從native調(diào)過來的状囱,

channeltype分別是flutter/systemmemoryPressure

image-20210916103914716.png
image-20210916103843272.png

6.調(diào)試一下engine看看怎么傳過來的。

全局搜一下engine源碼倘是,看起來是這個亭枷。

image-20210916104304137.png

lldb打上方法斷點看看什么時候調(diào):

image-20210916105009888.png

快知道最終原因了:

image-20210916105109496.png
image-20210916105141640.png

因為flutter_boost把engine.viewController設(shè)置為了nil,觸發(fā)了memoryPressure搀崭。

方法的源頭是detachFlutterEngineIfNeeded

detachFlutterEngineIfNeeded就是在vc dismiss的時候調(diào)用叨粘。

image-20210916104755214.png

7.到這更奇怪了,兩種方式都是dismiss瘤睹,為什么切換tab升敲,會重新動畫呢?

image-20210916105535275.png

結(jié)論

最終答案在這轰传,如果是當(dāng)前頁面push和pop會進(jìn)入attatchFlutterEngine的邏輯驴党,而在簡單場景下例如A->B->A detachFlutterEngine方法內(nèi)部因為判斷self.viewController.engine != self,所以就不會執(zhí)行之后的邏輯获茬。而嵌tabbar頁中flutter vc在flutterboost看起來港庄,也做了相同的邏輯倔既,一旦切出,我也默認(rèn)這個頁面銷毀了攘轩,不再進(jìn)行管理叉存。切換tab,F(xiàn)adeInImage重新做動畫的根本原因就是度帮,F(xiàn)lutterBoost在detachFlutterEngine把engine.viewcontroller置為了nil歼捏,觸發(fā)了memoryPressure(內(nèi)存壓力),把ImageCache清空了笨篷,導(dǎo)致雖然網(wǎng)絡(luò)圖片的緩存還在瞳秽,但是讓flutter誤以為需要重新加載。

稍微改一下代碼

image-20210916110126681.png
2021-09-16 11.01.43.gif

完美率翅。

暫時不知道官方這么寫的原因练俐,所以最后的解決方法,還是把動畫時間調(diào)成最短冕臭,讓人肉眼看不到圖片重新做動畫腺晾。

補充核心過程(假設(shè)A是tab-native,B是tab-flutter辜贵,B的圖片已經(jīng)加載完畢):

第一種情況(B->A->C->A->B)

第一步:回到A悯蝉,push一個flutter的C頁面,觸發(fā)memoryPressure(init)托慨,并且因為層級變化image觸發(fā)didChangeDependencies

image-20210916144339234.png

可以看到_cache清空了鼻由,但_liveImages中的網(wǎng)絡(luò)圖片對象還在,這個時候會把_liveImages的對象取出厚棵,重新放到_cache中蕉世。

image-20210916144742323.png

并且返回對象。這個時候_cache又恢復(fù)正常婆硬。

image-20210916144828593.png

之后因為image不需要在響應(yīng)動畫狠轻,所以移除通知

image-20210916153426636.png

再移除的過程中將liveImage清掉

image-20210916153507713.png

所以進(jìn)入C頁面的最后結(jié)果是

image-20210916153552069.png

第二步.C dismiss,觸發(fā)memoryPressure(engineDetach)彬犯,清了一把_cache

image-20210916153714071.png

這個時候什么緩存都沒了向楼,Image的key需要重新創(chuàng)建初始化,所以回到B會重新動畫躏嚎。

第二種情況:(B->C->B)

第一步同上。

第二步.C dismiss菩貌,不會engineDetach卢佣,所以不會觸發(fā)memoryPressure,所以回到B箭阶,直接拿緩存虚茶,不用重新創(chuàng)建戈鲁。

后續(xù)

給官方提了一個PR,新增vc keepalive屬性嘹叫,針對這種tab內(nèi)嵌的頁面進(jìn)行特殊管理婆殿。
https://github.com/alibaba/flutter_boost/pull/1422?w=1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市罩扇,隨后出現(xiàn)的幾起案子婆芦,更是在濱河造成了極大的恐慌,老刑警劉巖喂饥,帶你破解...
    沈念sama閱讀 210,835評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件消约,死亡現(xiàn)場離奇詭異,居然都是意外死亡员帮,警方通過查閱死者的電腦和手機或粮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捞高,“玉大人氯材,你說我怎么就攤上這事∠醺冢” “怎么了氢哮?”我有些...
    開封第一講書人閱讀 156,481評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辈讶。 經(jīng)常有香客問我命浴,道長,這世上最難降的妖魔是什么贱除? 我笑而不...
    開封第一講書人閱讀 56,303評論 1 282
  • 正文 為了忘掉前任生闲,我火速辦了婚禮,結(jié)果婚禮上月幌,老公的妹妹穿的比我還像新娘碍讯。我一直安慰自己,他們只是感情好扯躺,可當(dāng)我...
    茶點故事閱讀 65,375評論 5 384
  • 文/花漫 我一把揭開白布捉兴。 她就那樣靜靜地躺著,像睡著了一般录语。 火紅的嫁衣襯著肌膚如雪倍啥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,729評論 1 289
  • 那天澎埠,我揣著相機與錄音虽缕,去河邊找鬼。 笑死蒲稳,一個胖子當(dāng)著我的面吹牛氮趋,可吹牛的內(nèi)容都是我干的伍派。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼剩胁,長吁一口氣:“原來是場噩夢啊……” “哼诉植!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起昵观,我...
    開封第一講書人閱讀 37,633評論 0 266
  • 序言:老撾萬榮一對情侶失蹤晾腔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后索昂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體建车,經(jīng)...
    沈念sama閱讀 44,088評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,443評論 2 326
  • 正文 我和宋清朗相戀三年椒惨,在試婚紗的時候發(fā)現(xiàn)自己被綠了缤至。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,563評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡康谆,死狀恐怖领斥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沃暗,我是刑警寧澤月洛,帶...
    沈念sama閱讀 34,251評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站孽锥,受9級特大地震影響嚼黔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惜辑,卻給世界環(huán)境...
    茶點故事閱讀 39,827評論 3 312
  • 文/蒙蒙 一唬涧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盛撑,春花似錦碎节、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽域蜗。三九已至男公,卻和暖如春贴见,著一層夾襖步出監(jiān)牢的瞬間涯冠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評論 1 264
  • 我被黑心中介騙來泰國打工峡捡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留报腔,地道東北人蜈彼。 一個月前我還...
    沈念sama閱讀 46,240評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像总滩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子巡雨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,435評論 2 348

推薦閱讀更多精彩內(nèi)容