Flutter主流功能集成插件mainstream的使用

Flutter主流功能集成插件mainstream的使用

StreamBuilder 是 Flutter 中一个非常强大的小部件,它可以根据流(Stream)中的数据动态更新 UI。然而,StreamBuilder 并没有提供一种方法来接收流的 data/error/done 事件的回调。我们可能希望在这些事件发生时执行某些操作,例如更新 Navigator。这在 StreamBuilderbuilder 回调中实现是不可靠的,因为 Flutter 可能会多次调用 build() 方法。因此,我们需要额外的流监听器,但这需要创建一个 StatefulWidget 并取消流订阅。此外,如果我们的流不是广播流(意味着它不支持多个监听器),我们可能完全不能使用 StreamBuilder

问题

class Home extends StatefulWidget {
  [@override](/user/override)
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  StreamSubscription<FirebaseUser> _subscription;

  [@override](/user/override)
  void initState() {
    super.initState();
    _subscription = FirebaseAuth.instance.onAuthStateChanged.listen((event) {
      Navigator.of(context).popUntil((route) => route.isFirst);
    });
  }

  [@override](/user/override)
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return StreamBuilder<FirebaseUser>(
      stream: FirebaseAuth.instance.onAuthStateChanged,
      builder: (_context, snapshot) => snapshot.data.isAnonymous ? LoggedOut() : LoggedIn(),
    );
  }
}

解决方案

MainStream 小部件使用了与 StreamBuilder 相同的基础 StreamBuilderBase,但同时提供了额外的 onData/onError/onDone 回调。这些回调不会因小部件重建而重新触发。它还提供了构建器回调以构建互斥的 busy/data/error 小部件状态。

class Home extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MainStream<FirebaseUser>(
      stream: FirebaseAuth.instance.onAuthStateChanged,
      onData: (_) => Navigator.of(context).popUntil((r) => r.isFirst),
      dataBuilder: (_, data) => data.isAnonymous ? LoggedOut() : LoggedIn(),
    );
  }
}
  • 可以在 StatelessWidget 中使用。
  • 支持单订阅和广播流。
  • 提供了对传递给回调的数据的泛型类型安全。类型参数 <T> 可以省略,如果编译器可以推断出。

使用方法

final myStream = Stream&lt;int&gt;.periodic(Duration(seconds: 1), (x) =&gt; x).take(5);

class Home extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MainStream&lt;int&gt;(
      stream: myStream,
      onData: (data) =&gt; print(data),
      onError: (error) =&gt; showDialog(...),
      onDone: () =&gt; print('Done!'),
      busyBuilder: (_) =&gt; CircularProgressIndicator(),
      dataBuilder: (_, data) =&gt; Text(data.toString()),
      errorBuilder: (_, error) =&gt; Text(error.toString()),
    );
  }
}
  • stream 参数是必需的。
  • 可选的 busyBuilder 显示一个小部件,当 Stream 等待其第一个事件时。默认情况下,它显示一个居中的 CircularProgressIndicator
  • 可选的 dataBuilderStream 的最后一个事件是一个成功的数据负载时显示一个小部件。Stream<T> 的结果 T 值作为参数传递给回调。
  • 可选的 errorBuilderStream 的最后一个事件是一个错误时显示一个小部件,通常是一个 ErrorException
  • 可选的 onData 回调可用于处理成功数据事件,例如通过显示警报对话框或执行导航。这可以在 dataBuilder 之外或与之一起使用。这不会因小部件重建而重新触发。
  • 可选的 onError 回调可用于处理错误事件,例如通过显示警报对话框或将错误发送到日志记录提供程序。它可以单独使用或与 errorBuilder 一起使用。这不会因小部件重建而重新触发。
  • 可选的 onDone 回调可用于处理流的完成事件。这不会因小部件重建而重新触发。

示例代码

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // 这个小部件是你的应用程序的根。
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

final myStream = Stream&lt;int&gt;.periodic(Duration(seconds: 1), (x) =&gt; (x == 3) ? throw Exception('oops') : x).take(5);

class Home extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: MainStream&lt;int&gt;(
          stream: myStream,
          onData: (data) =&gt; print(data),
          onError: (error) =&gt; _showAlert(context, error.toString()),
          onDone: () =&gt; print('Done!'),
          busyBuilder: (_) =&gt; CircularProgressIndicator(),
          dataBuilder: (_, data) =&gt; Text(data.toString()),
          errorBuilder: (_, error) =&gt; Text(error.toString()),
        ),
      ),
    );
  }

  void _showAlert(BuildContext context, String text) {
    showDialog(
      context: context,
      builder: (_) {
        return AlertDialog(
          content: Text(text),
          actions: &lt;Widget&gt;[
            TextButton(
              child: Text('OK'),
              onPressed: () =&gt; Navigator.of(context).pop(),
            )
          ],
        );
      },
    );
  }
}

更多关于Flutter主流功能集成插件mainstream的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter主流功能集成插件mainstream的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,集成主流功能通常依赖于一系列高质量、社区维护的插件。mainstream 这个词并不是一个具体的Flutter插件名称,但我们可以理解为你想要集成一系列在Flutter应用中常用的功能插件。以下是一些主流功能的插件及其使用示例代码:

1. 网络请求:http 插件

用于发送HTTP请求,获取数据。

pubspec.yaml

dependencies:
  http: ^0.13.3

使用示例

import 'package:http/http.dart' as http;
import 'dart:convert';

Future<void> fetchData() async {
  final response = await http.get(Uri.parse('https://api.example.com/data'));

  if (response.statusCode == 200) {
    Map<String, dynamic> data = jsonDecode(response.body);
    print(data);
  } else {
    throw Exception('Failed to load data');
  }
}

2. 状态管理:provider 插件

用于在Flutter应用中管理应用状态。

pubspec.yaml

dependencies:
  provider: ^6.0.0

使用示例

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

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Counter()),
      ],
      child: MyApp(),
    ),
  );
}

class Counter with ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Counter')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '${Provider.of<Counter>(context).count}',
                style: Theme.of(context).textTheme.headline4,
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            Provider.of<Counter>(context, listen: false).increment();
          },
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

3. 图片选择:image_picker 插件

用于从设备图库或相机中选择图片。

pubspec.yaml

dependencies:
  image_picker: ^0.8.4+3

使用示例

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Image Picker')),
        body: Center(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File? _image;

  final ImagePicker _picker = ImagePicker();

  Future<void> _pickImage(ImageSource source) async {
    final pickedFile = await _picker.pickImage(source: source);

    setState(() {
      if (pickedFile != null) {
        _image = File(pickedFile!.path);
      } else {
        _image = null;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        _image == null
            ? Text('No image selected.')
            : Image.file(_image!),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: () => _pickImage(ImageSource.gallery),
          child: Text('Pick image from gallery'),
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: () => _pickImage(ImageSource.camera),
          child: Text('Pick image from camera'),
        ),
      ],
    );
  }
}

4. 本地存储:shared_preferences 插件

用于在设备上存储键值对数据。

pubspec.yaml

dependencies:
  shared_preferences: ^2.0.9

使用示例

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('SharedPreferences')),
        body: Center(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late SharedPreferences _preferences;

  @override
  void initState() {
    super.initState();
    _loadPreferences();
  }

  Future<void> _loadPreferences() async {
    _preferences = await SharedPreferences.getInstance();
    setState(() {});
  }

  Future<void> _saveData(String key, String value) async {
    await _preferences.setString(key, value);
  }

  Future<String?> _loadData(String key) async {
    return _preferences.getString(key);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: () async {
            await _saveData('myKey', 'myValue');
            final String? value = await _loadData('myKey');
            print(value);
          },
          child: Text('Save and Load Data'),
        ),
      ],
    );
  }
}

这些示例展示了如何在Flutter应用中集成和使用一些主流功能的插件。根据项目的具体需求,你可以进一步扩展和定制这些功能。

回到顶部