天天看點

Flutter BLoC 異步通信、BlocBuilder的基本使用、BlocProvider的初探

題記

—— 執劍天涯,從你的點滴積累開始,所及之處,必精益求精。

Flutter是谷歌推出的最新的移動開發架構。

【x1】微信公衆号的每日提醒 随時随記 每日積累 随心而過 【x2】各種系列的視訊教程 免費開源 關注 你不會迷路 【x3】系列文章 百萬 Demo 随時 複制粘貼 使用 在 Flutter 中可用于異步通信的方案有如下:

1 前言

BloC 全稱是 Business Logic Component(業務邏輯元件),主要作用就是将業務邏輯和UI元件分離開。

在Flutter項目開發中,一般的項目中,會有網絡請求的代碼與Widget建構的UI界面寫一起,随着業務的不斷積累,代碼量也越來越大,維護的複雜度也會随着增加。

BLoC模式可以将Widget建構UI的代碼與業務處理的代碼分離出來,在BLoC模式下的應用程式,一般會有全局的BLoC,每一個頁面也會對應有一個獨立的BLoC。

Flutter BLoC 異步通信、BlocBuilder的基本使用、BlocProvider的初探

使用BloC模式,Flutter項目應用裡的所有元件都在一個事件流,其中一部分元件可以訂閱事件,另一部分元件則消費事件

Flutter BLoC 異步通信、BlocBuilder的基本使用、BlocProvider的初探

2 BloC 的基本使用

BloC是一種架構模式也是一種程式設計思想,在Flutter中使用BloC時,首先要引入

bloc庫
dependencies:
  flutter_bloc: ^6.0.6           

然後将依賴庫拉取到本地

flutter packages get           

在Flutter BloC模式開發中常用元件有BlocBuilder、BlocProvider、BlocListener和BlocConsumer等等。

在這裡使用Bloc模式開發一個時間計時器 運作效果如下圖所示:

Flutter BLoC 異步通信、BlocBuilder的基本使用、BlocProvider的初探

首先來看程式入口,在這裡使用到了 BlocProvider ,BlocProvider相當于一個組合者,它将 Bloc 、事件、消費組合在一起,在本文章 第四小節有詳細概述,代碼如下:

///flutter應用程式中的入口函數
void main() => runApp(BlocMainApp());

///應用的根布局
class BlocMainApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ///建構Materia Desin 風格的應用程式
    return BlocProvider<CounterBloc>(
      create: (context) => CounterBloc(""),
      child: MaterialApp(
        ///Android應用程式中工作列中顯示應用的名稱
        title: "配制",
        theme: ThemeData(
          accentColor: Colors.blue,
          ///預設是 Brightness.light
          brightness: Brightness.light,
        ),
        ///預設的首頁面
        home: TestBlocTimePage(),
      ),
    );
  }
}
           
Flutter BLoC 異步通信、BlocBuilder的基本使用、BlocProvider的初探

對于 TestBlocTimePage 就是 MaterialApp中設定預設顯示的 home 首頁面,是自定義的一個 Widget 頁面,在這裡使用 Scaffold 來建構頁面主體,然後初始化了一個 計時器Timer,代碼如下:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:async';
import 'bloc_time.dart';

///Bloc 初探
class TestBlocTimePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _TestABPageState();
  }
}

class _TestABPageState extends State {
 
  ///計時器
  Timer _timer;
  @override
  void initState() {
    super.initState();
    ///間隔1秒執行時間
    _timer= Timer.periodic(Duration(milliseconds: 1000), (timer) {
      ///發送事件 
      BlocProvider.of<TimeCounterBloc>(context).add(0);
    });
  }


  @override
  void dispose() {
    super.dispose();
    ///取消計時器
    _timer.cancel();
  }
  @override
  Widget build(BuildContext context) {
    ///頁面主體腳手架
    return Scaffold(
      appBar: AppBar(
        title: Text("Bloc "),
      ),
      body:buildBlocBuilder(),
    );
  }

  ///代碼清單1-1
  /// 通過 BlocBuilder 來消費事件結果
  Widget buildBlocBuilder() {
    return BlocBuilder<TimeCounterBloc, String>(
      builder: (context, time) {
        ///在這裡 time 就是BloC回傳的資料處理結果
        ///當然在這裡是一個 String 類型
        return Container(
          ///外邊距
          margin: EdgeInsets.only(left: 12,top: 12),
          child: Text(
            '$time',
            style: TextStyle(fontSize: 22.0, color: Colors.red),
          ),
        );
      },
    );
  }
}
           

在這裡定義的 BlocBuilder,本文第三小節有分析。

定義的 Bloc 角色,代碼如下:

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
///Bolc 的泛型資料類型
///在這裡 int 代表輸入的事件類型
///      String 代表輸出的資料結果
class TimeCounterBloc extends Bloc<int, String> {
  ///預設構造
  ///[initialState]預設的資料
  TimeCounterBloc(String initialState) : super(initialState);

  ///業務邏輯處理 [event] 事件辨別
  @override
  Stream<String> mapEventToState(int event) async* {
    ///擷取目前的時間
    DateTime dateTime= DateTime.now();
    ///格式化時間 import 'package:intl/intl.dart';
    ///需要添加 intl 依賴
    String formatTime = DateFormat("HH:mm:ss").format(dateTime);
    ///發射更新資料
    yield formatTime;
  }
}           
Flutter BLoC 異步通信、BlocBuilder的基本使用、BlocProvider的初探

3 BlocBuilder

BlocBuilder與StreamBuilder的作用一樣,用來消費事件結果,就是顯示資料結果,它的建構建構如下:

class BlocBuilder<C extends Cubit<S>, S> extends BlocBuilderBase<C, S> {
  /// {@macro bloc_builder}
  const BlocBuilder({
    Key key,
    @required this.builder,
    C cubit,
    BlocBuilderCondition<S> buildWhen,
  })  : assert(builder != null),
        super(key: key, cubit: cubit, buildWhen: buildWhen);
  ... ...
  }           

builder 參數為必選參數,用來建構消費的 UI 視圖,它需要一個 BlocWidgetBuilder,BlocWidgetBuilder定義如下:

typedef BlocWidgetBuilder<S> = Widget Function(BuildContext context, S state);           

BlocWidgetBuilder 的入參數二 state 就是 BloC 中發射的資料。

buildWhen參數,用于向BlocBuilder提供可選的條件,傳回 true,那麼将調用state執行視圖的重新建構,如果傳回false,則不會執行視圖的重建操作。

Widget buildBlocBuilder() {
    return BlocBuilder<TimeCounterBloc, String>(
      ///條件判斷是否更新視圖
      /// 參數 previous 上一次的資料
      /// 參數 current 目前的資料
      buildWhen: (String previous,String current){
        print("previous $previous  current $current");
        return true;
      },
      ///入參 time 為BloC發射的資料
      builder: (context, time) {
        ///在這裡 time 就是BloC回傳的資料處理結果
        ///當然在這裡是一個 String 類型
        return Container(
          ///外邊距
          margin: EdgeInsets.only(left: 12,top: 12),
          child: Text(
            '$time',
            style: TextStyle(fontSize: 22.0, color: Colors.red),
          ),
        );
      },
    );
  }           

4 BlocProvider

BlocProvider相當于一個組合者,它将 Bloc 、事件、消費組合在一起,它是一個元件。

可以通過BlocProvider.of (context)向其子級提供bloc,如上述的 add 方法發送事件

BlocProvider.of<TimeCounterBloc>(context).add(0);           
5 MultiBlocProvider

MultiBlocProvider是一個用于将多個BlocProvider合并為一個BlocProvider的元件。

MultiBlocProvider(
  providers: [
    BlocProvider<BlocA>(
      create: (BuildContext context) => BlocA(),
    ),
    BlocProvider<BlocB>(
      create: (BuildContext context) => BlocB(),
    ),
    BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
    ),
  ],
  child: 子頁面視圖,
)           

然後在子頁面中 通過 BlocBuilder 分别引用不同的 Bloc 就可以,小編這也有 Demo

完畢

以小編的性格,要實作百萬Demo随時複制粘貼肯定是需要源碼的

  • BlocProvider Demo
  • MultiBlocProvider Demo

當然以小編的性格,肯定是要有視訊錄制的,目前正在錄制中,你可以關注一下

西瓜視訊 --- 早起的年輕人

随後會上傳

繼續閱讀