2019年9月28日 星期六

flutter 用 StreamBuilder 產生動態部件

StreamBuilder與FutureBuilder都是一個未來事件驅動的部件,他們都源自於 StatefulWidget, 因此他是一個動態部件, Future 是一次性的事件, 而 Stream 則是源源不斷的事件, 因此當未來只要完成一件事情時, 就簡單用 FutureBuilder, 若是處理源源不斷的資料流就要用 StreamBuilder. FutureBuilder 只有在事件完成時才創造出新部件,而 StreamBuild 在資料流發生事件時就創造出新部件,不用再另外寫一個繼承 StatefulWidget 的類型, 他們是由 Flutter 系統內監聽未來事件或是資料流做出反應創造出新部件, 比較特別的是StreamBuilder 與 FutureBuilder 是一種獨立於時間狀態的部件, 也不能用 setState 去改變狀態, 相較於 StatefulWidget 的部件, 同步於系統的時間狀態(最快大約是 1/60 秒的更新速率)必須用 setState 去同步系統作後續的部件更新運作截然不同, 但都具有非同步操作的特性,但要注意的是, 當要處理像是使用 Timer 之類的物件, 就只能用 StatefulWidget 去運作. 用 StreamBuilder 或是 FutureBuilder 創造動態部件的好處在於可以跟其他的部件在同一階層下享用物件內的資源來重建新部件, 就算放在靜態物件內也不失其獨立運作的動態本性,  StatefulWidget 是一個獨立的動態物件類型, 只能先透過建構式傳進資料, 例如餵進 callback Function 或是資料流建構出一個溝通管道, 後續再透過這些管道加以溝通,不像StreamBuilfer 或是 FutureBuilder 那麼簡單直接, StreamBuilder 應該是一種 BLoC 運作模式,可以搜索參考網路上更多關於 BLoC(Business Logic Component)的文章, 將運作邏輯與物件狀態分離的一種機制, 當程式內的部件過多, 或是部件之間交互作用太過複雜時, 就需理解出一套思考邏輯用於程式維護,但同時也很可能犯下一些常見的錯誤程式編寫方式, 例如宣告成整體區域變數作為溝通媒介, 造成程式邏輯雖然沒錯, 但畫面卻沒同步更新的狀況, 主要原因是變數分離後, 導致 setState 與要重建的部件不同步, 變數雖然改變了, 但畫面卻看不到, 詳述可參考 youtube 的影片:
https://www.youtube.com/watch?v=RS36gBEp8OI
// dart 模組程式
import 'package:flutter/material.dart';
mixin AAAA { // 當要混入 StatelessWidget 時, 特性常數必須 final, 讓同階層的部件共享資源
    final  a =3; // 公共變數
    final _style = TextStyle(fontSize: 24.0); // _  底線用意是同一模組下該變數可視,私有變數
    TextStyle  style( )  => _style;// 或是透過不含底線的方法 style( ) 將它公開
    void get dump => print(a); //  透過 getter 方法, 就不需後綴添加 ( )
}
void main(){      runApp(MyApp());    }
class MyApp extends StatelessWidget {// 靜態根部件
  @override Widget build(BuildContext context) => MaterialApp(
    debugShowCheckedModeBanner: false,
    theme : ThemeData.dark(),
    home  : ExamplePage()
  );
}
class ExamplePage extends StatelessWidget with AAAA {//第1層靜態部件,混入 AAAA 類型
  @override  Widget build(BuildContext context) => Scaffold(
     //內含  appBar 與 body 兩個部件, 用 StreamBuilder 創造出動態部件包進 AppBar 的title
      appBar: AppBar(title:  StreamBuilder(initialData: 0, // 初始值, 監聽資料流
                stream  : Stream<int>.periodic(Duration(milliseconds: 500), (_)=>_).take(10),
                builder : (BuildContext context, AsyncSnapshot<int> snapshot) {
                  final data = snapshot.data;
                  switch(snapshot.connectionState) {
                    case ConnectionState.waiting: return Text('Wait...', style: _style);//初始部件
                    // case ConnectionState.done : return Text('Finish.', style:_style);//私有資源
                    // case ConnectionState.none:
                    // case ConnectionState.active:
                    default: return Text('StreamBuilder $data + mixin $a', style: _style);//更新部件
                  }                 
                }
              )),
      body : Text('mixin: $a', style:_style) // 靜態部件, 取用公共資源 a, 與私有資源 _style
  );
}

沒有留言:

張貼留言

使用 pcie 轉接器連接 nvme SSD

之前 AM4 主機板使用 pcie ssd, 但主機板故障了沒辦法上網, 只好翻出以前買的 FM2 舊主機板, 想辦法讓老主機復活, 但舊主機板沒有 nvme 的界面, 因此上網買了 pcie 轉接器用來連接 nvme ssd, 遺憾的是 grub2 bootloader 無法識...