Created
September 4, 2025 17:11
-
-
Save rena2019/9fe349e6eae13dca3e6570a7216b2704 to your computer and use it in GitHub Desktop.
Flutter Stream example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
//wrapper class for progress + data | |
class DataWithProgress<T> { | |
final T? data; | |
final int progress; // 0..100 | |
final Object? error; | |
final bool done; | |
DataWithProgress({this.data, required this.progress, this.error, this.done = false}); | |
} | |
// Producer (async* Beispiel) | |
Stream<DataWithProgress<int>> produce() async* { | |
int total = 5; | |
for (int i = 1; i <= total; i++) { | |
await Future.delayed(Duration(seconds: 1)); | |
int progress = ((i / total) * 100).round(); | |
yield DataWithProgress(data: i, progress: progress); | |
} | |
// optional: endgültiger Done-Event | |
yield DataWithProgress(progress: 100, done: true); | |
} | |
void main() async { | |
final controller = StreamController<DataWithProgress>(); | |
// Listener | |
print("1. Listener ---"); | |
controller.stream.listen((value) { | |
print('Received progress: ${value.progress}%, data: ${value.data}'); | |
}, onDone: () => print('Stream closed (onDone)'),); | |
// Adding data | |
controller.sink.add(DataWithProgress(progress: 1)); | |
await Future.delayed(Duration(seconds: 1)); | |
controller.sink.add(DataWithProgress(progress: 33, data: 1)); | |
await Future.delayed(Duration(seconds: 2)); | |
controller.sink.add(DataWithProgress(progress: 66, data: 2)); | |
await Future.delayed(Duration(seconds: 1)); | |
controller.sink.add(DataWithProgress(progress: 99, data: 3)); | |
controller.sink.add(DataWithProgress(progress: 100, done: true)); | |
// Closing the stream | |
controller.close(); | |
//consume stream with async* function | |
print("2. consume stream with async* function ---"); | |
await for (final event in produce()) { | |
if (event.data != null) print('Data: ${event.data} — ${event.progress}%'); | |
if (event.done) print('Producer signaled done'); | |
} | |
print('Stream finished'); | |
//UI | |
print("3. UI ---"); | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return const MaterialApp(home: ProgressDemoPage()); | |
} | |
} | |
class ProgressDemoPage extends StatefulWidget { | |
const ProgressDemoPage({super.key}); | |
@override | |
State<ProgressDemoPage> createState() => _ProgressDemoPageState(); | |
} | |
class _ProgressDemoPageState extends State<ProgressDemoPage> { | |
late Stream<DataWithProgress<int>> _stream; | |
@override | |
void initState() { | |
super.initState(); | |
_stream = produce(); | |
} | |
void _restart() { | |
setState(() { | |
_stream = produce(); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: const Text('Progress Stream Demo')), | |
body: Center( | |
child: StreamBuilder<DataWithProgress<int>>( | |
stream: _stream, | |
builder: (context, snapshot) { | |
if (snapshot.connectionState == ConnectionState.waiting) { | |
return const Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
CircularProgressIndicator(), | |
SizedBox(height: 12), | |
Text('Warte auf erste Updates...'), | |
], | |
); | |
} else if (snapshot.hasError) { | |
return Text('Error: ${snapshot.error}'); | |
} else if (snapshot.hasData) { | |
final e = snapshot.data!; | |
final displayData = e.data != null ? 'Data: ${e.data}' : 'No data'; | |
return Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Text(displayData, style: const TextStyle(fontSize: 24)), | |
const SizedBox(height: 12), | |
SizedBox( | |
width: 250, | |
child: LinearProgressIndicator(value: e.progress / 100), | |
), | |
const SizedBox(height: 8), | |
Text('${e.progress}%'), | |
if (e.done) const Padding( | |
padding: EdgeInsets.only(top: 8.0), | |
child: Text('Fertig', style: TextStyle(color: Colors.green)), | |
), | |
], | |
); | |
} else { | |
return const Text('No data available'); | |
} | |
}, | |
), | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: _restart, | |
child: const Icon(Icons.replay), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment