Flutter数据流加载插件stream_loader的使用

发布于 1周前 作者 caililin 来自 Flutter

Flutter数据流加载插件stream_loader的使用

stream_loader 是一个用于在Flutter应用中异步加载内容的插件,它结合了Dart Stream和RxDart来实现。该插件提供了简单易用的反应式状态管理容器。

作者

Petrus Nguyễn Thái Học

开始使用

在你的Flutter项目中,将以下依赖添加到pubspec.yaml文件中:

dependencies:
  ...
  stream_loader: <latest_version>

请确保替换<latest_version>为当前可用的最新版本号。

示例

使用方法

1. 模型与API定义

首先定义你的模型和API接口。这里以评论为例:

import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';

abstract class Comment implements Built<Comment, CommentBuilder> {
  // 定义你的字段
}

class Api {
  final http.Client client;

  Api(this.client);

  Stream<BuiltList<Comment>> getComments() async* {
    // 实现获取评论列表的方法
  }

  Stream<Comment> getCommentBy({required int id}) async* {
    // 实现根据ID获取特定评论的方法
  }
}
final api = Api(http.Client());

2. 创建LoaderWidget加载评论列表

下面是如何使用LoaderWidget从API加载评论列表的例子:

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

// 假设已经定义了Comment类和Api类

LoaderWidget<BuiltList<Comment>>(
  blocProvider: () => LoaderBloc(
    loaderFunction: api.getComments,
    refresherFunction: api.getComments,
    initialContent: <Comment>[].build(),
    logger: print,
  ),
  messageHandler: (context, message, bloc) {
    message.fold(
      onFetchFailure: (error, stackTrace) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Fetch error'))),
      onFetchSuccess: (_) {},
      onRefreshSuccess: (data) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Refresh success'))),
      onRefreshFailure: (error, stackTrace) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Refresh error'))),
    );
  },
  builder: (context, state, bloc) {
    if (state.error != null) {
      return Center(child: Text('Error: ${state.error}'));
    }
    if (state.isLoading) {
      return Center(child: CircularProgressIndicator());
    }
    return RefreshIndicator(
      onRefresh: bloc.refresh,
      child: ListView.builder(
        itemCount: state.content.length,
        itemBuilder: (context, index) => ListTile(title: Text(state.content[index].toString())),
      ),
    );
  },
);

3. 创建LoaderWidget加载单个评论详情

同样地,也可以用来加载单个评论详情:

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

final comment = ...; // 获取你要查看的评论对象
final loadDetail = () => api.getCommentBy(id: comment.id);

LoaderWidget<Comment>(
  blocProvider: () => LoaderBloc(
    loaderFunction: loadDetail,
    refresherFunction: loadDetail,
    initialContent: comment,
    logger: print,
  ),
  messageHandler: (context, message, bloc) {
    message.fold(
      onFetchFailure: (_, __) {},
      onFetchSuccess: (_) {},
      onRefreshFailure: (_, __) {},
      onRefreshSuccess: (_) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Refresh success'))),
    );
  },
  builder: (context, state, bloc) {
    return RefreshIndicator(
      onRefresh: bloc.refresh,
      child: Column(
        children: [
          Text(state.content.toString()),
        ],
      ),
    );
  },
);

注意事项

你可以不通过LoaderWidget直接使用LoaderBloc,如下所示:

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

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

class _CommentsPageState extends State<CommentsPage> {
  late LoaderBloc<BuiltList<Comment>> bloc;

  [@override](/user/override)
  void didChangeDependencies() {
    super.didChangeDependencies();
    bloc = LoaderBloc(
      loaderFunction: api.getComments,
      refresherFunction: api.getComments,
      initialContent: <Comment>[].build(),
      logger: print,
    )..fetch();
  }

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return StreamBuilder<LoaderState<BuiltList<Comment>>>(
      stream: bloc.state$,
      initialData: bloc.state$.value,
      builder: (context, snapshot) {
        final state = snapshot.data!;
        if (state.error != null) {
          return Center(child: Text('Error: ${state.error}'));
        }
        if (state.isLoading) {
          return Center(child: CircularProgressIndicator());
        }
        return RefreshIndicator(
          onRefresh: bloc.refresh,
          child: ListView.builder(
            itemCount: state.content.length,
            itemBuilder: (context, index) => ListTile(title: Text(state.content[index].toString())),
          ),
        );
      },
    );
  }
}

更多关于Flutter数据流加载插件stream_loader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据流加载插件stream_loader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用stream_loader插件进行数据流加载的示例代码。stream_loader是一个用于处理异步数据流加载的Flutter插件,它可以帮助开发者更方便地管理数据流的加载状态(如加载中、加载完成、加载失败)。

首先,确保你已经在pubspec.yaml文件中添加了stream_loader依赖:

dependencies:
  flutter:
    sdk: flutter
  stream_loader: ^最新版本号  # 请替换为最新的版本号

然后,运行flutter pub get来安装依赖。

接下来是一个示例代码,展示了如何使用stream_loader来加载数据流:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Stream Loader Example'),
        ),
        body: StreamLoaderExample(),
      ),
    );
  }
}

class StreamLoaderExample extends StatefulWidget {
  @override
  _StreamLoaderExampleState createState() => _StreamLoaderExampleState();
}

class _StreamLoaderExampleState extends State<StreamLoaderExample> {
  final StreamController<int> _controller = StreamController<int>();
  StreamLoader<int> _streamLoader;

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

    // Initialize StreamLoader with a stream
    _streamLoader = StreamLoader<int>(
      stream: _createDataStream(),
      onLoadData: (data) {
        // This is called when data is emitted from the stream
        print('Data loaded: $data');
      },
      onError: (error, stackTrace) {
        // This is called when an error occurs in the stream
        print('Error: $error');
      },
      onCompleted: () {
        // This is called when the stream completes
        print('Stream completed');
      },
    );

    // Start listening to the stream
    _streamLoader.listen();
  }

  @override
  void dispose() {
    _controller.close();
    super.dispose();
  }

  Stream<int> _createDataStream() {
    return _controller.stream.map((event) async* {
      // Simulate some async work with a delay
      await Future.delayed(Duration(seconds: 1));
      yield event;
    }).take(5); // Emit 5 events for demonstration
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        // Display the loading state
        if (_streamLoader.isLoading)
          CircularProgressIndicator(),

        // Display the data once loaded
        if (_streamLoader.hasData)
          Text('Data: ${_streamLoader.data}'),

        // Display an error message if there's an error
        if (_streamLoader.hasError)
          Text('Error: ${_streamLoader.error?.toString()}'),

        // Button to trigger data loading (for demonstration purposes)
        ElevatedButton(
          onPressed: () {
            // Reset the stream loader and emit new data
            _controller.add(1); // This will trigger the stream to emit new data
          },
          child: Text('Load Data'),
        ),
      ],
    );
  }
}

在这个示例中:

  1. 我们创建了一个StreamController<int>来模拟数据流的来源。
  2. StreamLoader<int>被初始化并传入一个数据流,以及处理数据、错误和完成状态的回调。
  3. initState方法中,我们开始监听这个数据流。
  4. 根据数据流的加载状态(加载中、加载完成、加载失败),我们在UI中显示不同的组件(如进度指示器、数据文本或错误消息)。
  5. 通过按钮触发新的数据流加载,以演示如何使用这个插件进行动态数据加载。

请根据你的实际需求调整这个示例代码。

回到顶部