I don't have much experience developing Flutter apps, but I have a good understanding of what a thread is in Dart.
What you are interested in can be implemented in the following way.
[](https://i.sstatic.net/cwdUhn1g.gif)
Example (your code with a small addition):
```dart
import 'package:flutter/material.dart';
import 'package:multitasking/misc/pause.dart';
import 'package:multitasking/multitasking.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(title: 'Flutter Demo', home: MyHomePage1());
}
}
class MyHomePage1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final cts = CancellationTokenSource();
final pts = PauseTokenSource();
return Scaffold(
appBar: AppBar(title: Text("APP DEMO")),
body: Center(
child: StreamBuilder(
stream: _createStream(
20,
).asCancelable(cts.token, pauseToken: pts.token),
builder: (context, AsyncSnapshot<int> snapshot) {
var text = '';
if (snapshot.error != null) {
debugPrint("error code? ${snapshot.error}");
/* I want to stop (or cancel) _stream here */
cts.cancel();
} else {
final data = snapshot.data;
text = data == null ? '' : data.toString();
}
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Timer: $text', style: TextStyle(fontSize: 20)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
pts.pause();
},
child: const Text('Pause'),
),
ElevatedButton(
onPressed: () {
pts.resume();
},
child: const Text('Resume'),
),
ElevatedButton(
onPressed: () {
cts.cancel();
},
child: const Text('Cancel'),
),
],
),
],
);
},
),
),
);
}
Stream<int> _createStream(int val) {
Stream<int> stream = Stream.periodic(Duration(seconds: 1), (int i) {
int ret = val - i;
if (ret == 0) {
throw ("error ");
/*Or, I want to stop (or cancel) _stream here */
}
return val - i;
});
return stream;
}
}
```
You can use [async][1] to easily control the stream This is how you can do it.
First create a StreamSubsctiprion like this
StreamSubscription<QuerySnapshot>? _eventStream;
and then set a listener for your snapshots stream.
here is how you can store stream query snapshot
Stream<QuerySnapshot> streamSub =_fireStore
.collection(...)
.doc(...)
.snapshots();
add listener for your stream like this
_eventStream = streamSub.listen((snapshot) => _eventStream);
Then you can use your event stream to cancel, pause and resume your stream like this
_eventStream!.pause();
_eventStream!.cancel();
_eventStream!.resume();
[1]: https://pub.dev/packages/async
here is my final code
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
class MainScreen extends State<PaymentScreen> {
StreamSubscription<QuerySnapshot>? _eventStream;
@override
Widget build(BuildContext context) {
Stream<QuerySnapshot> myStream = FirebaseFirestore.instance.collection('Users').snapshots();
return Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
StreamBuilder<QuerySnapshot>(
stream: myStream,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return Column(
children:
snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['firstName']),
);
}).toList(),
);
},
),
FloatingActionButton.extended(
onPressed: () {
_eventStream = myStream.listen((snapshot) => _eventStream);
try {
_eventStream!.pause();
print('paused');
} catch (e, s) {
print(s);
}
},
label: const Text("Pause Stream"),
),
],
),
),
);
}
}
<!-- end snippet -->