欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

javascript入門教程,JavaScript快速入門

Flutter開發(fā)性能提升之:如何避免Widget重復(fù)Build

問(wèn)題描述:

發(fā)展壯大離不開廣大客戶長(zhǎng)期以來(lái)的信賴與支持,我們將始終秉承“誠(chéng)信為本、服務(wù)至上”的服務(wù)理念,堅(jiān)持“二合一”的優(yōu)良服務(wù)模式,真誠(chéng)服務(wù)每家企業(yè),認(rèn)真做好每個(gè)細(xì)節(jié),不斷完善自我,成就企業(yè),實(shí)現(xiàn)共贏。行業(yè)涉及房屋鑒定等,在網(wǎng)站建設(shè)公司網(wǎng)絡(luò)營(yíng)銷推廣、WAP手機(jī)網(wǎng)站、VI設(shè)計(jì)、軟件開發(fā)等項(xiàng)目上具有豐富的設(shè)計(jì)經(jīng)驗(yàn)。

在Flutter開發(fā)的過(guò)程中,當(dāng)我們獲取到新的數(shù)據(jù)或者數(shù)據(jù)發(fā)生變化,需要去執(zhí)行setState進(jìn)行頁(yè)面刷新的時(shí)候,經(jīng)常會(huì)出現(xiàn)不必要的子節(jié)點(diǎn)Widget也進(jìn)行了build,但實(shí)際上我們是不想讓它再次build,出現(xiàn)這些問(wèn)題的典型情況是在使用FutureBuilder的時(shí)候,例如:

在上面這個(gè)示例中,如果再次調(diào)用Build方法,則會(huì)觸發(fā)httpCall()的方法。

那么怎樣才能避免不必要的部件構(gòu)建呢?

分析:

在Flutter中,Build方法的設(shè)計(jì)方式是pure/without side effects,書面意思是無(wú)副作用的/純粹的,簡(jiǎn)單點(diǎn)理解我們可以將其含義看作不會(huì)對(duì)外部的方法或者變量產(chǎn)生影響的。這是因?yàn)樵S多外部因素能夠觸發(fā)新的小部件的構(gòu)建,例如這些情況:

但是,這也意味著Build方法可以不去觸發(fā)httpCall()的方法或者不修改任何狀態(tài)。

解決

回歸問(wèn)題,當(dāng)前我們面臨的問(wèn)題是Build方法造成了副作用,也就是造成了無(wú)關(guān)的Build調(diào)用麻煩。

所以,只要我們使Build方法保持純粹/無(wú)副作用,這樣就算多少次調(diào)用它,也不會(huì)對(duì)其他Widget的Build方法產(chǎn)生影響。

在上面的示例中,我們將Widget轉(zhuǎn)換為StatefulWidget,然后提取httpCall()到initState中,這樣問(wèn)題就解決了

另外,還可以使一個(gè)Widget能夠在不強(qiáng)迫其子部件也構(gòu)建的情況下進(jìn)行重新構(gòu)建。

在Widget的實(shí)例保持不變時(shí);Flutter會(huì)有意識(shí)的不去重建子部件。這意味著我們可以緩存Widget樹的某些部分,以防止不必要的重新構(gòu)建。

最簡(jiǎn)單的方法是使用const修飾構(gòu)造函數(shù):

由于const的修飾,即使調(diào)用了數(shù)百次build,DecoratedBox的實(shí)例也將保持不變。

或者你可以這樣使用以達(dá)到相同的結(jié)果:

在這個(gè)例子中,當(dāng)StreamBuilder收到新值的通知時(shí),即使StreamBuilder的Column進(jìn)行了重構(gòu),subtree也不會(huì)進(jìn)行重構(gòu)。這是因?yàn)橛捎陂]包,MyWidget的實(shí)例沒(méi)有改變。

這種模式在動(dòng)畫中經(jīng)常使用。典型的是使用AnimatedBuilder和所有的*Transition時(shí),例如AlignTransition。

我們還可以將subtree存儲(chǔ)到類的一個(gè)字段中,但是并不推薦你這樣做,因?yàn)樗鼤?huì)破壞Flutter的熱重載。

Flutter中的StatefulWidget及其生命周期

狀態(tài)可變的 widget 。

通過(guò)其類的定義能夠看到 StatefulWidget 配置 StatefulElement 。

State 是 StatefulWidget 的內(nèi)部邏輯與狀態(tài),由 StatefulWidget 的 createState 創(chuàng)建。

StatefulWidget 實(shí)例本身是不可變的, 但是 StatefulWidget 將其可變的狀態(tài),存儲(chǔ)在與之關(guān)聯(lián)的 State 對(duì)象中。

不管什么時(shí)候,只要在樹中 mount 一個(gè)新的 StatefulElement ,必然需要注入一個(gè) StatefulWidget ,注入一個(gè) StatefulWidget 時(shí), framework 都會(huì)調(diào)用一次 createState 方法。

其實(shí),在 StatefulElement 構(gòu)造的時(shí)候,就會(huì)調(diào)用 createState ,創(chuàng)建 _state 對(duì)象,( _state 是 StatefulElement 的變量)并且在 StatefulElement 的初始化方法中為 _state 關(guān)聯(lián)當(dāng)前的 StatefulElement 和用以配置 StatefulElement 的 StatefulWidget 。

StatefulElement 初始化方法如下:

這意味著如果 StatefulWidget 被插入到樹中的多個(gè)位置,則會(huì)有多個(gè) State 對(duì)象分別與它們關(guān)聯(lián)。

關(guān)于此類的定義如下:

描述: 重寫此方法以執(zhí)行初始化。

場(chǎng)景: 如果 State 的 build 方法依賴于本身可以改變狀態(tài)的對(duì)象時(shí)。(例如 ChangeNotifier 或 Stream ,或者可以訂閱并接收通知的其他對(duì)象)正確的方式是:

注意點(diǎn): 此方法中不能使用 BuildContext.dependOnInheritedWidgetOfExactType 。但是此方法被調(diào)用后會(huì)立即調(diào)用 didChangeDependencies ,在 didChangeDependencies 可以使用 BuildContext.dependOnInheritedWidgetOfExactType 。

調(diào)用時(shí)機(jī): StatefulElement ,首次插入樹中時(shí)會(huì)調(diào)用此方法,在 build 方法調(diào)用之前調(diào)用。

描述: StatefulElement 通過(guò)此方法返回的 widget 并通過(guò)調(diào)用 updateChild 來(lái)更新自己。

調(diào)用時(shí)機(jī): framework 調(diào)用此方法的幾個(gè)不同的場(chǎng)景如下:

描述: StatefulElement 存在,并且符合 Widget.canUpdate 的情況下對(duì) StatefulWidget 進(jìn)行更新。

調(diào)用時(shí)機(jī): 不論何時(shí)只要 StatefulElement 的配置 widget 改變的時(shí)候就會(huì)調(diào)用。

注意: didUpdateWidget 方法最終會(huì)調(diào)用 build 方法,因此在此方法中調(diào)用 setState 是多余的。如果重寫此方法,請(qǐng)確保調(diào)用 super.didUpdateWidget(oldWidget) 。

調(diào)用時(shí)機(jī): 當(dāng)此 State 對(duì)象的依賴項(xiàng)( InheritedWidget )更改時(shí)調(diào)用。

描述: 用于開發(fā)階段 hot reload 。

調(diào)用時(shí)機(jī): hot reload 時(shí)調(diào)用,調(diào)用后 build 方法也將被調(diào)用。無(wú)需在此方法中做任何操作。

調(diào)用時(shí)機(jī): 當(dāng) StatefulElement 從樹中移除的時(shí)候會(huì)調(diào)用。

調(diào)用時(shí)機(jī): 當(dāng) StatefulElement 從樹中 unmount 的時(shí)候會(huì)調(diào)用。

StatefulWidget 用以配置 StatefulElement ,但在這兩者之間的 State 承接了 StatefulElement 的生命周期,而 StatefulWidget 僅僅只是連接了 State 與 StatefulElement 的不可變的實(shí)例,因此 StatefulWidget 的生命周期,依賴于 StatefulElement ,而 State 卻是其最簡(jiǎn)單直接的體現(xiàn)形式。

為了能更好的理解 StatefulWidget 的生命周期,我畫了一張關(guān)于 State 、 StatefulElement 、 Component 、 Element 的關(guān)系圖。

第十六章:Flutter數(shù)據(jù)存儲(chǔ)

Flutter的數(shù)據(jù)存儲(chǔ)分為三類

Preference相當(dāng)于iOS的NSUserDefaults,其實(shí)也是按plist的方式存儲(chǔ)的

step1:添加依賴

step2:pub get

step3:導(dǎo)入頭文件

在path_provider中有三個(gè)獲取文件路徑的方法:

- getTemporaryDirectory()

://獲取應(yīng)用緩存目錄,等同iOS的NSTemporaryDirectory()和Android的getCacheDir() 方法。

- getApplicationDocumentsDirectory():

//獲取應(yīng)用文件目錄類似于iOS的NSDocumentDirectory和Android上的 AppData目錄。

step1:添加依賴

step2:pub get

step3:導(dǎo)入頭文件

Flutter 之 文件操作(二十九)

Dart的 IO 庫(kù)包含了文件讀寫的相關(guān)類,它屬于 Dart 語(yǔ)法標(biāo)準(zhǔn)的一部分,所以通過(guò) Dart IO 庫(kù),無(wú)論是 Dart VM 下的腳本還是 Flutter,都是通過(guò) Dart IO 庫(kù)來(lái)操作文件的,不過(guò)和 Dart VM 相比,F(xiàn)lutter 有一個(gè)重要差異是文件系統(tǒng)路徑不同,這是因?yàn)镈art VM 是運(yùn)行在 PC 或服務(wù)器操作系統(tǒng)下,而 Flutter 是運(yùn)行在移動(dòng)操作系統(tǒng)中,他們的文件系統(tǒng)會(huì)有一些差異。

Android 和 iOS 的應(yīng)用存儲(chǔ)目錄不同, PathProvider 插件提供了一種平臺(tái)透明的方式來(lái)訪問(wèn)設(shè)備文件系統(tǒng)上的常用位置。該類當(dāng)前支持訪問(wèn)兩個(gè)文件系統(tǒng)位置:

File代表一個(gè)整體的文件,他有三個(gè)構(gòu)造函數(shù),分別是:

文件讀取本身有兩種形式,一種是文本,一種是二進(jìn)制。

2.2.1 讀取文本內(nèi)容

如果是文本文件,F(xiàn)ile提供了readAsString、readAsLines、readAsStringSync、readAsLinesSync方法,讀取文本內(nèi)容

readAsString 一次性讀取所有文本

readAsLines 一行行的讀取文本

結(jié)果返回的是一個(gè)List,list中表示文件每行的內(nèi)容

readAsStringSync、readAsLinesSync同步讀取文本

2.2.2 讀取二進(jìn)制內(nèi)容

如果文件是二進(jìn)制,那么可以使用readAsBytes或者同步的方法readAsBytesSync:

dart中表示二進(jìn)制有一個(gè)專門的類型叫做Uint8List,他實(shí)際上表示的是一個(gè)int的List。

上面提到的讀取方式,都是一次性讀取整個(gè)文件,缺點(diǎn)就是如果文件太大的話,可能造成內(nèi)存空間的壓力。

所以File為我們提供了另外一種讀取文件的方法,流的形式來(lái)讀取文件.

示例

dart提供了open和openSync兩個(gè)方法來(lái)進(jìn)行隨機(jī)文件讀寫:

寫入和文件讀取一樣,可以一次性寫入或者獲得一個(gè)寫入句柄,然后再寫入。

一次性寫入的方法有四種,分別對(duì)應(yīng)字符串和二進(jìn)制

句柄形式可以調(diào)用openWrite方法,返回一個(gè)IOSink對(duì)象,然后通過(guò)這個(gè)對(duì)象進(jìn)行寫入:

默認(rèn)情況下寫入是會(huì)覆蓋整個(gè)文件的,但是可以通過(guò)下面的方式來(lái)更改寫入模式:

雖然dart中所有的異常都是運(yùn)行時(shí)異常,但是和java一樣,要想手動(dòng)處理文件讀寫中的異常,則可以使用try,catch:

我們還是以計(jì)數(shù)器為例,實(shí)現(xiàn)在應(yīng)用退出重啟后可以恢復(fù)點(diǎn)擊次數(shù)。 這里,我們使用文件來(lái)保存數(shù)據(jù):

1.引入PathProvider插件;在pubspec.yaml文件中添加如下聲明:

執(zhí)行 flutter pub get

2.實(shí)現(xiàn)如下

參考:

iOS開發(fā)Flutter探索-State狀態(tài)保存(10)

有時(shí)候我們不希望某個(gè)頁(yè)面每次打開時(shí)都重新加載,比如就我們之前的Tabbar結(jié)構(gòu)的頁(yè)面,每當(dāng)我們?cè)谇袚QTab的時(shí)候都會(huì)執(zhí)行 void initState() ,這就意味著頁(yè)面每次都會(huì)重新渲染,之所以這樣就是因?yàn)槲覀兊?State 狀態(tài)沒(méi)有保存,如下圖所示:

[沒(méi)有狀態(tài)保存效果圖]

給當(dāng)前 State 類添加一個(gè)擴(kuò)展(這里就用擴(kuò)展這個(gè)詞吧,其實(shí)類似于iOS下的 Category ),一個(gè)系統(tǒng)的擴(kuò)展類 AutomaticKeepAliveClientMixin ,并重寫 wantKeepAlive 方法,讓一個(gè)普通的 State 類,具有保存狀態(tài)的能力。

在Dart語(yǔ)法中通過(guò)使用 with 關(guān)鍵字來(lái)添加擴(kuò)展:

bool get wantKeepAlive = true; 之后,當(dāng)前 State 就具備保存能力了,也就意味著重復(fù)切換Tab后, void initState() 就不會(huì)重復(fù)執(zhí)行了(由原來(lái)的 viewWillAppear() 變成了 viewDidLoad() )。

按照上面方式修改后,發(fā)現(xiàn)切換Tab后 void initState() 依然重復(fù)執(zhí)行了,這是為什么吶?這里我們看下我們之前 root_page.dart 里面是如何配置我們的tabbar結(jié)構(gòu)的:

這里我們是通過(guò)一個(gè) _viewControllers 的List,把4個(gè)子頁(yè)面放在了里面,全局有一個(gè) _currentIndex ,當(dāng) onTap 回調(diào)后后,更新 _currentIndex 的值,執(zhí)行 setState () 后, body 對(duì)應(yīng)的 widget 頁(yè)面發(fā)生改變。而問(wèn)題也就出在這里,當(dāng) body 部分發(fā)生改變時(shí),根據(jù)Flutter的底層渲染邏輯,這里會(huì)移除掉之前的 Widget ,并重新創(chuàng)建新的 Widget ,我們之前在 _viewControllers 放的子頁(yè)面,并不像iOS下是一個(gè)實(shí)例對(duì)象,存在就直接拿來(lái)使用。在Flutter 中 setState () 后界面會(huì)被重新繪制,而 body 部分只知道我要渲染一個(gè)什么樣的 widget ,而該類型的 widget 每次都是會(huì)重新創(chuàng)建,這也就意味著我們?cè)赥ab切換時(shí),每次都是重新創(chuàng)建,所以每次都執(zhí)行了 initState() 。

顯然我們現(xiàn)在的方式是不合理的,那在Flutter中如何管理這樣的子頁(yè)面,而避免重復(fù)渲染吶?

這就要用到一個(gè)新的部件了: PageView() ,內(nèi)部的2個(gè)關(guān)鍵屬性:

子頁(yè)面切換通過(guò) _controller.jumpToPage(index); 來(lái)實(shí)現(xiàn)。

這樣子頁(yè)面也就不會(huì)重新創(chuàng)建渲染了,我們的狀態(tài)保存也就能正常實(shí)現(xiàn)了。

學(xué)習(xí)是一個(gè)循序漸進(jìn)的過(guò)程,我們總是在踩坑中不斷的前行,把坑填平了也就意味著我們?cè)谶@個(gè)新的東西面前立了足,就可能進(jìn)行更多為什么的探索了。

flutter provider的理解

provider 是flutter 中的狀態(tài)管理 開源庫(kù);

存儲(chǔ)的數(shù)據(jù)對(duì)象 必須extends ChangeNotifier;下層widget 通過(guò) Provider.of(context) 函數(shù) 獲取model對(duì)象 ,并且可以建立依賴關(guān)系;當(dāng)數(shù)據(jù)對(duì)象發(fā)生變化時(shí),依賴的widget 會(huì)重新build,像不像InheritedWidget Provider 沒(méi)錯(cuò) 下層widget就是 封裝了InheritedWidget

主要 通過(guò) Provider.ofT(context) 函數(shù),來(lái)獲取;

推薦使用 Provider.of而不是 Consumer,因?yàn)?listen默認(rèn)為true,也就是說(shuō) 默認(rèn) 依賴于 持有數(shù)據(jù)model的widget 對(duì)應(yīng)的element;

數(shù)據(jù)類 可繼承的 ChangeNotifier,本身和privider框架 沒(méi)有關(guān)系;

ChangeNotifier 是 flutter框架 提供的工具類, 用來(lái)實(shí)現(xiàn)一對(duì)多的訂閱通知功能。

文章名稱:javascript入門教程,JavaScript快速入門
網(wǎng)頁(yè)路徑:http://chinadenli.net/article16/dsiojdg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站動(dòng)態(tài)網(wǎng)站小程序開發(fā)Google云服務(wù)器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)