关于flutter中的状态管理(三)(Stream版Provid

2022-04-02  本文已影响0人  晨曦中的花豹

上一篇有个想法就是以ChangeNotifier为主, InheritedWidget来管理ChangeNotifier的思路,最终夭折,这篇主要搞一下使用StreamController和InheritedWidget组合方式来实现状态管理,依然是InheritedWidget管理StreamController, StreamController来最终完成状态的管理.
(原创想法,如有雷同纯属巧合)
先思考我们要的是什么效果,我需要在全局套一个InheritedWidget来传递StreamController以及数据,而且是数据与StreamController是一一对应的,所以我们可以将数据与StreamController放到一起,而且为了我的数据扩展,我可以这样来定义

class CountModel<T> extends StreamObject {
  int count = 0;
  add() {
    count++;
    update();
  }
}

class StreamObject {
  final StreamController? _streamController = StreamController();
  StreamSink? get sink => _streamController?.sink;
  Stream? get stream => _streamController?.stream;
  void update() {
    sink?.add("");
  }
}

将数据类型继承自基类,基类中管理StreamController
当然这里我们在StreamBuilder中使用的是count本身,所以sink.add只是用来触发重构的,所以这里随便传什么都可以,前提是你不再使用snapshot,而是使用数据本身
创建InheritedWidget

class PutStreamController<T extends StreamObject> extends InheritedWidget {

  T model;

  PutStreamController(
      {required this.model, Key? key, required Widget child })
      : super(key: key, child: child);

  static T? of<T extends StreamObject>(BuildContext context, {bool listen = true}) {
    PutStreamController<T>? inheritedWidget;
    inheritedWidget = ((context.getElementForInheritedWidgetOfExactType<PutStreamController<T>>())
        ?.widget as PutStreamController<T>?);

    return inheritedWidget?.model;
  }

  @override
  bool updateShouldNotify(covariant PutStreamController oldWidget) {
    return false;
  }
}

这里只是使用到了InheritedWidget传递数据的能力,所以updateShouldNotify可以返回false,以及我只需要通过getElementForInheritedWidgetOfExactType查询到我的数据即可
使用起来是这样的

void main() {
  Get.put(TestGetController());
  runApp(
      PutStreamController(
        model: CountModel(),
        child: const MyApp(),
      )
  );
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: StreamBuilder(
          stream: PutStreamController.of<CountModel>(context)?.stream,
          builder: (context, AsyncSnapshot snapshot) {
            return Text("${PutStreamController.of<CountModel>(context)?.count}");
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          PutStreamController.of<CountModel>(context)?.add();
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

现在整体来看是可以了,但是我一点都不想把StreamController暴露出来,所以可以对StreamBuilder进行封装

typedef AsyncModelBuilder<T> = Widget Function(BuildContext context, T model);

class ModelBuilder<T extends StreamObject> extends StatelessWidget {
  ModelBuilder({required this.builder,Key? key}) : super(key: key);
  AsyncModelBuilder<T?> builder;

  @override
  Widget build(BuildContext context) {
    T? model = PutStreamController.of<T>(context);
    return StreamBuilder(
      stream: model?.stream,
      builder: (context, _) => builder(context,model),
    );
  }
}

这样调用就变得简单了

ModelBuilder<CountModel>(
  builder: (context,model)=>Text("${model?.count}"),
)

而之前是这样的...

StreamBuilder(
      stream: PutStreamController.of<CountModel>(context)?.stream,
      builder: (context, AsyncSnapshot snapshot) {
        return Text("${PutStreamController.of<CountModel>(context)?.count}");
      },
),

到这里一个基于StreamController和InheritedWidget的状态管理就完成了
最终的代码

import 'dart:async';
import 'package:flutter/material.dart';

void main() {
  runApp(PutStreamController(
    model: CountModel(),
    child: const MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: ModelBuilder<CountModel>(
          builder: (context,model)=>Text("${model?.count}"),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          PutStreamController.of<CountModel>(context)?.add();
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

class PutStreamController<T extends StreamObject> extends InheritedWidget {
  final T model;

  const PutStreamController({required this.model, Key? key, required Widget child})
      : super(key: key, child: child);

  static T? of<T extends StreamObject>(BuildContext context,
      {bool listen = true}) {
    PutStreamController<T>? inheritedWidget;
    inheritedWidget = ((context
            .getElementForInheritedWidgetOfExactType<PutStreamController<T>>())
        ?.widget as PutStreamController<T>?);

    return inheritedWidget?.model;
  }

  @override
  bool updateShouldNotify(covariant PutStreamController oldWidget) {
    return false;
  }
}

class CountModel extends StreamObject {
  int count = 0;
  add() {
    count++;
    update();
  }
}

class StreamObject {

  final StreamController? _streamController = StreamController();

  StreamSink? get sink => _streamController?.sink;

  Stream? get stream => _streamController?.stream;

  void update() {
    sink?.add("");
  }
}

typedef AsyncModelBuilder<T> = Widget Function(BuildContext context, T? model);

class ModelBuilder<T extends StreamObject> extends StatelessWidget {
  const ModelBuilder({required this.builder,Key? key}) : super(key: key);
  final AsyncModelBuilder<T> builder;

  @override
  Widget build(BuildContext context) {
    T? model = PutStreamController.of<T>(context);
    return StreamBuilder(
      stream: model?.stream,
      builder: (context, _) => builder(context,model),
    );
  }
}

这里你只需要关注于你的CountModel就可以了
Provider是基于ChangeNotifier和InheritedWidget, ChangeNotifier来刷新InheritedWidget从而实现对应数据的刷新,主角是InheritedWidget,而今天的Stream与InheritedWidget的组合却是,以Stream为主的,所以我称之为Stream版本Provider

上一篇下一篇

猜你喜欢

热点阅读