Flutter 使用流来分离数据和UI

发布于 10 天前 作者 sinazl 18 次浏览 最后一次编辑是 10 天前 来自 分享

Flutter 使用流来分离数据和UI

•video "lib\main.dart"

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
import 'package:flutter_demo/src/list.dart';

void main() {
 final list = ListService();
 runApp(MyApp(list: list));
}

class MyApp extends StatelessWidget {
 MyApp({Key key, this.list}) : super(key: key);

 ListService list;

 [@override](/user/override)
 Widget build(BuildContext context) {
   return MaterialApp(
     home: MyHome(list: list),
   );
 }
}

class MyHome extends StatefulWidget {
 MyHome({Key key, this.list}) : super(key: key);

 final ListService list;

 [@override](/user/override)
 _MyHomeState createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
 [@override](/user/override)
 void dispose() {
   widget.list.dispose();
   super.dispose();
 }

 [@override](/user/override)
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('Flutter Demo'),
     ),
     floatingActionButton: FloatingActionButton(
       child: Icon(Icons.add),
       onPressed: () =>
           widget.list.addOneWord(generateWordPairs().take(1).elementAt(0)),
     ),
     body: StreamBuilder<Set<WordPair>>(
       stream: widget.list.lists,
       initialData: Set<WordPair>(),
       builder: (context, snapshot) {
         if (snapshot.connectionState == ConnectionState.waiting) {
           return Center(
             child: CircularProgressIndicator(),
           );
         }

         return ListView(
           children: <Widget>[
             for (WordPair w in snapshot.data)
               ListTile(
                 title: Text(
                   w.asLowerCase,
                   style: TextStyle(fontSize: 28),
                 ),
                 trailing: IconButton(
                   onPressed: () => widget.list.delOneWord.add(w),
                   icon: Icon(Icons.close),
                 ),
               ),
           ],
         );
       },
     ),
   );
 }
}

"lib\src\list.dart"

import 'dart:async';
import 'package:rxdart/rxdart.dart';
import 'package:english_words/english_words.dart';

class ListService {
  Stream<Set<WordPair>> get lists => _listsSubject.stream;
  // BehaviorSubject: Subject的变体,需要初始值并在订阅时发出其当前值。
  final _listsSubject = BehaviorSubject<Set<WordPair>>();
  var _lists = Set<WordPair>();

  Sink<WordPair> get delOneWord => _delOneWordController.sink;
  // StreamController: 该控制器允许在其流上发送数据
  final _delOneWordController = StreamController<WordPair>();

  ListService() {
    _getList().then((_) {
      _listsSubject.add(_lists);
    });

    _delOneWordController.stream.listen((WordPair w) {
      _lists.remove(w);
      _listsSubject.add(_lists);
    });
  }

  void dispose() {
    _delOneWordController.close();
  }

  // 模拟异步获取列个列表数据
  Future<Null> _getList() async {
    await Future.delayed(Duration(seconds: 4));
    _lists = generateWordPairs().take(5).toSet();
  }

  /// 向列表添加单个数据
  void addOneWord(WordPair w) {
    _lists.add(w);
    _listsSubject.add(_lists);
  }

  /// 删除列表的指定数据
  // void delOneWord(WordPair w) {
  //   _lists.remove(w);
  //   _listsSubject.add(_lists);
  // }
}

在StatefulWidget中初始化流服务

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DashPage(),
    );
  }
}

class DashPage extends StatefulWidget {
  [@override](/user/override)
  _DashPageState createState() => _DashPageState();
}

class _DashPageState extends State<DashPage> {
  int _currentIndex = 0;
  final PageController _controller = PageController();
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: _currentIndex,
        fixedColor: Colors.purple,
        onTap: (int index) {
          setState(() {
            _currentIndex = index;
            _controller.jumpToPage(index);
          });
        },
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
              icon: Icon(Icons.home),
              activeIcon: Icon(Icons.home),
              title: Text("Home")),
          BottomNavigationBarItem(
              icon: Icon(Icons.search),
              activeIcon: Icon(Icons.search),
              title: Text("Search")),
        ],
      ),
      body: PageView(
        controller: _controller,
        onPageChanged: (int index) {
          setState(() {
            _currentIndex = index;
          });
        },
        children: <Widget>[
          HomePage(),
          Center(child: Text('Search Page')),
        ],
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  [@override](/user/override)
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  HomeService homeService;

  [@override](/user/override)
  void initState() {
    super.initState();
    homeService = HomeService();
  }

  [@override](/user/override)
  void dispose() {
    homeService?.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('demo'),
      ),
      body: StreamBuilder<int>(
        stream: homeService.index$,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Text('0');
          }
          int index = snapshot.data;
          return Column(
            children: <Widget>[
              Text(index.toString()),
              OutlineButton(
                child: Text('add'),
                onPressed: () {
                  homeService.add(index + 1);
                },
              ),
            ],
          );
        },
      ),
    );
  }
}

class HomeService {
  Stream<int> get index$ => _indexSubject.stream;
  final _indexSubject = BehaviorSubject<int>.seeded(0);
  Function(int) get add => _indexSubject.sink.add;

  dispose() {
    _indexSubject.close();
  }
}
回到顶部