Dart Streams - Flutter in Focus

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
♪ (jazzy music) ♪ Hey, everybody, and welcome to the third video in our "Flutter in Focus" series on asynchronous coding patterns in Dart. In this episode, I'm going to cover one of the fundamentals of reactive programming, streams. If you saw our previous video on futures, you may remember that each future represents a single value, either an error or data that it delivers asynchronously. Streams work similarly, only instead of a single thing, they can deliver zero or more values and errors over time. If you think about the way a single value relates to an iterator of the same type, that's how a future relates to a stream. Just like with futures, the key is deciding in advance here's what to do when a piece of data is ready, when there's an error, and when the stream completes. And the Dart event loop is still running the show. If you're using <i>files.openRead</i> method to read data from a file, for example, it returns a stream. Chunks of data are read from disk and arrive at the event loop. <i>dart:io</i> looks at them and says, "Ah, I've got somebody waiting for this," adds the data to the stream, and it pops out in your app's code. When another piece of data arrives, in it goes and out it comes. Timer-based streams, streaming data from a network socket-- they work with the event loop too using clock and network events. Okay, let's talk about how to work with data provided by a stream. Say I have a class that will give me a stream that kicks out a new integer once per second-- one, two, three, four, five. I can use the <i>listen</i> method to subscribe to the stream. I give it a function, and every time a new value is emitted by the stream, my function gets called and prints it. That's how <i>listen</i> works. One important thing to note is that, by default, streams are set up for single subscription. They hold onto their values until someone subscribes, and they only allow a single listener for their entire lifespan. If you try to listen to one twice, you'll get an exception. Fortunately, Dart also offers broadcast streams. You can use the <i>asBroadcastStream</i> method to make a broadcast stream from a single subscription one. They work the same as single subscription streams, but they can have multiple listeners. And if nobody's listening when a piece of data is ready, it gets tossed out. Let's go back to that first listen call though because there are a couple more things to talk about. I mentioned earlier that streams can produce errors just like futures can-- by adding an <i>onError</i> method you can catch and process any errors. There's also a <i>cancelOnError</i> property that's true by default, but can be set to false to keep the subscription going even after an error. And there's an <i>onDone</i> method you can use to execute some code when the stream is finished sending data, such as when a file has been completely read. With all four of those properties combined, you can be ready in advance for whatever happens. Before moving on to the next section, I should mention that the little subscription object that's so far gone unnoticed has some useful methods of its own. You can use it to pause, resume and even cancel the flow of data. Okay, so that's a quick look at how you can use <i>listen</i> to subscribe to a stream and receive data events. Now we get to talk about what makes streams really cool: manipulating them. Once you've got data in a stream, there are a lot of operations that suddenly become fluent and elegant. Let's go back to that number stream from earlier. I can use a method called <i>map</i> to take each value from the stream and convert it, on the fly, into something else. I give <i>map</i> a function to do the conversion, and it returns a new stream, typed to match the return value of my function. Instead of a stream of ints, I now have a stream of strings. I can throw a <i>listen</i> call on the end, give it the <i>print</i> function and now I'm printing strings directly off the stream, asynchronously, as they arrive. There's a ton of methods you can chain up like this. If I only want to print the even numbers, for example, I can use <i>where</i> to filter the stream. I give it a test function that returns a Boolean for each element, and it returns a new stream that only includes values that pass that test. <i>distinct</i> is another good one. If I have an app that uses a <i>ReduxStore</i>, that store emits new app state objects in an <i>onChange</i> stream. I can use <i>map</i> to convert that stream of state objects to a stream of <i>ViewModels</i> for one particular part of my app. Then I can use the <i>distinct</i> method to get a stream that filters out consecutive identical values-- in case the store kicks out a change that doesn't affect the subset of data in <i>MyViewModel.</i> Then I can <i>listen</i> and update my UI whenever I get a new <i>ViewModel</i>. There are a bunch of additional methods built into Dart that can use to shape and modify your streams. Plus, when you're ready for even more advanced stuff, there's the Async package, maintained by the Dart team and available on Pub. It has classes that can merge two streams together, cache results and perform other types of stream-based wizardry. Alright, there's one more advanced topic that deserves a mention here, and that's how to create streams of your own. Just like with futures, most of the time, you're going to be working with streams created for you by network libraries, file libraries, state management and so on. But you can make your own as well using a stream controller. Let's go back to that number creator we'd been using so far. Here's the actual code for it. As you can see, it keeps a running count, and it uses a timer to increment that count each second. The interesting bit though is the stream controller. A stream controller creates a brand new stream from scratch and gives you access to both ends of it. There's the stream end itself where data arrives. We've been using that one throughout this video, and there's the <i>sink</i>, which is where new data gets added to the stream. <i>NumberCreator</i> here uses both of them. When the timer goes off, it adds the latest count to the controller's sink, and then it exposes the controller's stream with a <i>public</i> property so other objects can subscribe to it. Now that we've covered creating, manipulating, and listening to streams, let's talk about how to put them to work building widgets in Flutter. If you saw the previous video on futures, you may remember <i>FutureBuilder</i>. You give it a <i>future</i> and a <i>builder</i> method, and it builds widgets based on the state of the future. For streams, there's a similar widget called <i>StreamBuilder</i>. Give it a stream, like the one from <i>NumberCreator</i> and a <i>builder</i> method, and it will rebuild its children whenever a new value is emitted by the stream. The <i>snapshot</i> parameter is an async snapshot just like with <i>FutureBuilder</i>. You can check its <i>connectionState</i> property to see if the stream hasn't yet sent any data, or if it's completely finished. And you can use the <i>hasError</i> property to see if the latest value is an error and handle data values as well. The main thing is just to make sure your builder knows how to handle all the possible states of the stream. Once you've got that, it can react to whatever the stream does. Okay, that's all we've got for this video, but there are more coming in the series. Next up, we'll be talking about <i>Async</i> and <i>Await</i>. They're two key words Dart offers to help you keep your asynchronous code tight and easy to read. So be on the lookout for that, and head to <i>Dart.dev</i> and <i>Flutter.dev</i> for more info on Dart and Flutter. ♪ (music) ♪ Hey, if you enjoyed that video, try these others or subscribe to the Flutter channel, it's Google's new portable UI toolkit. There's a button around here somewhere. ♪ (music) ♪
Info
Channel: Flutter
Views: 170,998
Rating: undefined out of 5
Keywords: Dart streams, Dart futures, Dart async, Dart isolates, Asynchronous dart, Dart stream API, Flutter, Flutter in focus, Asynchronous programming, Google, building widgets, event loop, developers, StreamController, StreamBuilder, FutureBuilder, dart language, fundamentals of reactive coding, Stateless widgets, Stateful widgets, GDS: Yes;
Id: nQBpOIHE4eE
Channel Id: undefined
Length: 8min 0sec (480 seconds)
Published: Fri Jun 28 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.