Introducing Stream
Asynchronous programming is a common term in programming. With the Dart programming language, we are used to the Future class which provides a computation that is not completed immediately and will announce the result when ready, which only does it once. Instead Stream is an asynchronous stream of events and allows us to listen to these events as they are fired from the stream.
A stream is a sequence of asynchronous events.
Stream classification
- There are 2 types of Stream
- Single subscription streams
- Broadcast streams
The basic understanding is that Single subscription streams can only listen once. (If there is an event listening from somewhere else or a 2nd time or more, an error will be raised). Broadcast streams , on the other hand, can listen anywhere.
123456789101112131415161718<span class="token comment">//Sử dụng controller</span><span class="token comment">//**Single subscription streams</span><span class="token class-name">StreamController</span> streamController <span class="token operator">=</span> <span class="token class-name">StreamController</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span><span class="token class-name">Stream</span> stream <span class="token operator">=</span> streamController <span class="token punctuation">.</span> stream <span class="token punctuation">;</span><span class="token comment">//Broadcast streams-</span><span class="token class-name">StreamController</span> broadcastStreamController <span class="token operator">=</span> <span class="token class-name">StreamController</span> <span class="token punctuation">.</span> <span class="token function">broadcast</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span><span class="token class-name">Stream</span> stream <span class="token operator">=</span> broadcastStreamController <span class="token punctuation">.</span> stream <span class="token punctuation">;</span><span class="token comment">//Sử dụng async*</span><span class="token class-name">Stream</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> <span class="token function">countStream</span> <span class="token punctuation">(</span> int to <span class="token punctuation">)</span> <span class="token keyword">async*</span> <span class="token punctuation">{</span><span class="token keyword">for</span> <span class="token punctuation">(</span> int i <span class="token operator">=</span> <span class="token number">1</span> <span class="token punctuation">;</span> i <span class="token operator"><=</span> to <span class="token punctuation">;</span> i <span class="token operator">++</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">yield</span> i <span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">//yield -> bắn ra một event</span><span class="token comment">//yield* -> bắn ra 1 stream**</span>
Methods
- The power of Stream not only makes asynchronous programming easy, but it also has very powerful support methods such as filter, transform…
- See more at https://dart.dev/tutorials/language/streams
- Support library: extension for Rxdart . stream
- Refer to https://reactivex.io/ to learn about Reactivex/Functional reactive programming to learn about mechanism, how it works, how to use (supports many languages)
There is a small question: So what is the difference between these 2 types of Stream?
Why use Stream
- Stream is a core Dart library/api.
- → Easy to create Plugins (Split repo)
- → Master the technology
- Stream matches Flutter’s *declarative” style. (*** compared to the Imperative way in Native) and the MVVM model.
- Reduce dependency on 3rd party libraries.
- → Avoid errors when changing version
- → Reduce app size
- Some libraries like block, getx have mechanism that depends on Stream.
Building interfaces using StreamBuilder
StreamBuilder listens for Stream changes and refreshes the interface.
To use StreamBuilder need to call
1 2 3 4 5 6 7 | <span class="token keyword">const</span> <span class="token class-name">StreamBuilder</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token class-name">Key</span> <span class="token operator">?</span> key <span class="token punctuation">,</span> <span class="token class-name">Stream</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> <span class="token operator">?</span> stream <span class="token punctuation">,</span> <span class="token class-name">T</span> <span class="token operator">?</span> initialData <span class="token punctuation">,</span> required <span class="token class-name">AsyncWidgetBuilder</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> builder <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> |
Meaning of Parameters:
T? initialData : default value, if not passed in, is it considered not to have received data from Stream Stream<T>? stream : pass Stream to listen for and be processed at the required builder function AsyncWidgetBuilder<T> builder: Interface builder is set here
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | builder <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token class-name">BuildContext</span> context <span class="token punctuation">,</span> <span class="token class-name">AsyncSnapshot</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> snapshot <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//return Widget here;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">AsyncSnapshot</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token comment">/// Creates an [AsyncSnapshot] with the specified [connectionState],</span> <span class="token comment">/// and optionally either [data] or [error] with an optional [stackTrace]</span> <span class="token comment">/// (but not both data and error).</span> <span class="token keyword">const</span> <span class="token class-name">AsyncSnapshot</span> <span class="token punctuation">.</span> <span class="token function">_</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> connectionState <span class="token punctuation">,</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token punctuation">,</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> error <span class="token punctuation">,</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> stackTrace <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">assert</span> <span class="token punctuation">(</span> connectionState <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token keyword">assert</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token punctuation">(</span> data <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> error <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token keyword">assert</span> <span class="token punctuation">(</span> stackTrace <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> error <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
When building the UI, pay attention to the snapshot component in the builder
- Check ConnectionState to see connection status with Stream
- snapshot.hasError and snapshot.error: Check for errors and get errors. (Use
addError
to fire the error event) - snapshot.hasData and snapshot.data: Check for data and get data. (Use
add
to shoot out data)
ConnectionStates
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <span class="token comment">/// The state of connection to an asynchronous computation.</span> <span class="token comment">///</span> <span class="token comment">/// The usual flow of state is as follows:</span> <span class="token comment">///</span> <span class="token comment">/// 1. [none], maybe with some initial data.</span> <span class="token comment">/// 2. [waiting], indicating that the asynchronous operation has begun,</span> <span class="token comment">/// typically with the data being null.</span> <span class="token comment">/// 3. [active], with data being non-null, and possible changing over time.</span> <span class="token comment">/// 4. [done], with data being non-null.</span> <span class="token comment">///</span> <span class="token comment">/// See also:</span> <span class="token comment">///</span> <span class="token comment">/// * [AsyncSnapshot], which augments a connection state with information</span> <span class="token comment">/// received from the asynchronous computation.</span> <span class="token keyword">enum</span> <span class="token class-name">ConnectionState</span> <span class="token punctuation">{</span> <span class="token comment">/// Not currently connected to any asynchronous computation.</span> <span class="token comment">///</span> <span class="token comment">/// For example, a [FutureBuilder] whose [FutureBuilder.future] is null.</span> none <span class="token punctuation">,</span> <span class="token comment">/// Connected to an asynchronous computation and awaiting interaction.</span> waiting <span class="token punctuation">,</span> <span class="token comment">/// Connected to an active asynchronous computation.</span> <span class="token comment">///</span> <span class="token comment">/// For example, a [Stream] that has returned at least one value, but is not</span> <span class="token comment">/// yet done.</span> active <span class="token punctuation">,</span> <span class="token comment">/// Connected to a terminated asynchronous computation.</span> done <span class="token punctuation">,</span> <span class="token punctuation">}</span> |
- When not casting Stream to StreamBuilder (meaning Stream is null) → none
- When passing Stream ( initialData can be null or not) and have not added events → waiting
- When transmitting Stream and adding events → active
- When casting Stream and close() → done
Interface handler example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <span class="token class-name">StreamBuilder</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> <span class="token punctuation">(</span> stream <span class="token punctuation">:</span> stream <span class="token punctuation">,</span> builder <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token class-name">BuildContext</span> context <span class="token punctuation">,</span> <span class="token class-name">AsyncSnapshot</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> snapshot <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> snapshot <span class="token punctuation">.</span> connectionState <span class="token operator">==</span> <span class="token class-name">ConnectionState</span> <span class="token punctuation">.</span> waiting <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token class-name">CircularProgressIndicator</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> snapshot <span class="token punctuation">.</span> connectionState <span class="token operator">==</span> <span class="token class-name">ConnectionState</span> <span class="token punctuation">.</span> active <span class="token operator">||</span> snapshot <span class="token punctuation">.</span> connectionState <span class="token operator">==</span> <span class="token class-name">ConnectionState</span> <span class="token punctuation">.</span> done <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> snapshot <span class="token punctuation">.</span> hasError <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">*</span> <span class="token operator">*</span> <span class="token comment">//<-- Kiểm tra có lỗi**</span> <span class="token keyword">return</span> <span class="token keyword">const</span> <span class="token class-name">Text</span> <span class="token punctuation">(</span> <span class="token string">'Error'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> snapshot <span class="token punctuation">.</span> hasData <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">*</span> <span class="token operator">*</span> <span class="token comment">//<-- Kiểm tra có data**</span> <span class="token keyword">return</span> <span class="token class-name">Text</span> <span class="token punctuation">(</span> snapshot <span class="token punctuation">.</span> data <span class="token punctuation">.</span> <span class="token function">toString</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token operator">*</span> <span class="token operator">*</span> <span class="token comment">//<-- Lấy data**</span> style <span class="token punctuation">:</span> <span class="token keyword">const</span> <span class="token class-name">TextStyle</span> <span class="token punctuation">(</span> color <span class="token punctuation">:</span> <span class="token class-name">Colors</span> <span class="token punctuation">.</span> red <span class="token punctuation">,</span> fontSize <span class="token punctuation">:</span> <span class="token number">40</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">const</span> <span class="token class-name">Text</span> <span class="token punctuation">(</span> <span class="token string">'Empty data'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token class-name">Text</span> <span class="token punctuation">(</span> <span class="token string">'State: ${snapshot.connectionState}'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> |
[Demo] Building a countdown application using Stream
Demo below does not handle error states </aside>
Basic features:
Start – Pause – Resume – Refresh
Getting Started UI
UI Once Started
Steps to take
Declarations and functions are written in State of StatefulWidget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">class</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token keyword">extends</span> <span class="token class-name">StatefulWidget</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token class-name">Key</span> <span class="token operator">?</span> key <span class="token punctuation">,</span> required <span class="token keyword">this</span> <span class="token punctuation">.</span> seconds <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">super</span> <span class="token punctuation">(</span> key <span class="token punctuation">:</span> key <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">final</span> int seconds <span class="token punctuation">;</span> <span class="token metadata symbol">@override</span> <span class="token class-name">State</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token punctuation">></span></span> <span class="token function">createState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token class-name">CountDownCustomCubitPageState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">CountDownCustomCubitPageState</span> <span class="token keyword">extends</span> <span class="token class-name">State</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token comment">/* Code here */</span> <span class="token punctuation">}</span> |
- Create StreamController to manage data flow
1 2 3 4 | <span class="token keyword">final</span> <span class="token class-name">StreamController</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> _timeStreamController <span class="token operator">=</span> <span class="token class-name">StreamController</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">Stream</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> <span class="token keyword">get</span> _timeStream <span class="token operator">=</span> <span class="token operator">></span> _timeStreamController <span class="token punctuation">.</span> stream <span class="token punctuation">;</span> |
- Create StreamSubscription to manage the countdown
1 2 3 4 | _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">pause</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//tạm dừng</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">resume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//tiếp tục</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">cancel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//huỷ bỏ</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <span class="token class-name">StreamSubscription</span> <span class="token operator">?</span> _timeSubscription <span class="token punctuation">;</span> <span class="token keyword">void</span> <span class="token function">_onStart</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timeSubscription <span class="token operator">=</span> <span class="token class-name">Stream</span> <span class="token punctuation">.</span> <span class="token function">periodic</span> <span class="token punctuation">(</span> <span class="token keyword">const</span> <span class="token class-name">Duration</span> <span class="token punctuation">(</span> seconds <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> computationCount <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> _start <span class="token operator">-</span> computationCount <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> event <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timeStreamController <span class="token punctuation">.</span> <span class="token function">add</span> <span class="token punctuation">(</span> event <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> event <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">_onFinish</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//nhớ _timeSubscription?.dispose(); ở dispose()</span> <span class="token keyword">void</span> <span class="token function">_onResume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> isPaused <span class="token operator">?</span> <span class="token operator">?</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">resume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onPause</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token punctuation">(</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> isPaused <span class="token operator">?</span> <span class="token operator">?</span> <span class="token boolean">true</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">pause</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onFinish</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">cancel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> _timeSubscription <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onReset</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timeSubscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">cancel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> _timeSubscription <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token punctuation">;</span> _timeStreamController <span class="token punctuation">.</span> <span class="token function">add</span> <span class="token punctuation">(</span> _start <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Stream.periodic(**const** Duration(seconds: 1), (computationCount) => **_start** - computationCount)
creates a Stream that returns a value periodically after 1 second.
** _timeStreamController**.add(event);
add new time to Stream
- Display data on the interface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <span class="token class-name">StreamBuilder</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> <span class="token punctuation">(</span> initialData <span class="token punctuation">:</span> _start <span class="token punctuation">,</span> stream <span class="token punctuation">:</span> _timeStream <span class="token punctuation">,</span> builder <span class="token punctuation">:</span> <span class="token punctuation">(</span> context <span class="token punctuation">,</span> snapshot <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> snapshot <span class="token punctuation">.</span> hasData <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">final</span> int time <span class="token operator">=</span> snapshot <span class="token punctuation">.</span> data <span class="token operator">!</span> <span class="token punctuation">;</span> <span class="token keyword">var</span> separateWidget <span class="token operator">=</span> <span class="token class-name">Padding</span> <span class="token punctuation">(</span> padding <span class="token punctuation">:</span> <span class="token keyword">const</span> <span class="token class-name">EdgeInsets</span> <span class="token punctuation">.</span> <span class="token function">symmetric</span> <span class="token punctuation">(</span> horizontal <span class="token punctuation">:</span> <span class="token number">4</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> child <span class="token punctuation">:</span> <span class="token class-name">Text</span> <span class="token punctuation">(</span> <span class="token string">':'</span> <span class="token punctuation">,</span> style <span class="token punctuation">:</span> <span class="token class-name">Theme</span> <span class="token punctuation">.</span> <span class="token function">of</span> <span class="token punctuation">(</span> context <span class="token punctuation">)</span> <span class="token punctuation">.</span> textTheme <span class="token punctuation">.</span> headline2 <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">copyWith</span> <span class="token punctuation">(</span> fontFamily <span class="token punctuation">:</span> <span class="token string">'BlackOpsOne'</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> textAlign <span class="token punctuation">:</span> <span class="token class-name">TextAlign</span> <span class="token punctuation">.</span> center <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token class-name">Row</span> <span class="token punctuation">(</span> mainAxisSize <span class="token punctuation">:</span> <span class="token class-name">MainAxisSize</span> <span class="token punctuation">.</span> min <span class="token punctuation">,</span> crossAxisAlignment <span class="token punctuation">:</span> <span class="token class-name">CrossAxisAlignment</span> <span class="token punctuation">.</span> center <span class="token punctuation">,</span> children <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> hour <span class="token punctuation">.</span> tens <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> hour <span class="token punctuation">.</span> ones <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> separateWidget <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> minute <span class="token punctuation">.</span> tens <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> minute <span class="token punctuation">.</span> ones <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> separateWidget <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> second <span class="token punctuation">.</span> tens <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> second <span class="token punctuation">.</span> ones <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">const</span> <span class="token class-name">SizedBox</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> |
- Extension get time information from type int
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <span class="token keyword">extension</span> <span class="token class-name">IntToTime</span> <span class="token keyword">on</span> int <span class="token punctuation">{</span> <span class="token comment">///lấy thông tin giờ</span> int <span class="token keyword">get</span> hour <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">_getHour</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> int <span class="token function">_getHour</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token operator">/</span> <span class="token number">3600</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// return Duration(seconds: this).inHours;</span> <span class="token punctuation">}</span> <span class="token comment">///lấy thông tin giờ</span> int <span class="token keyword">get</span> minute <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">_getMinute</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> int <span class="token function">_getMinute</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token operator">/</span> <span class="token number">60</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">floor</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">60</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">///lấy thông tin giây</span> int <span class="token keyword">get</span> second <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">_getSecond</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> int <span class="token function">_getSecond</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span> <span class="token operator">%</span> <span class="token number">60</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">///format hiển thị số ở hàng chục</span> int <span class="token keyword">get</span> tens <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">_getTens</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> int <span class="token function">_getTens</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token operator">>=</span> <span class="token number">10</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token operator">-</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token operator">%</span> <span class="token number">10</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">10</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">round</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">///format hiển thị số ở hàng đơn vị</span> int <span class="token keyword">get</span> ones <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">_getOnes</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> int <span class="token function">_getOnes</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span> <span class="token operator">%</span> <span class="token number">10</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
- In order
giúp cho các công việc không thực hiện lại công việc nó đang thực hiện
, call the functions through the streamController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <span class="token metadata symbol">@override</span> <span class="token keyword">void</span> <span class="token function">initState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">initState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setTime</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">///việc quản lý các sự kiện bằng stream ở đây</span> <span class="token comment">///giúp cho các công việc không thực hiện lại công việc nó đang thực hiện</span> <span class="token comment">///bằng hàm distinct()</span> _functionSubscription <span class="token operator">=</span> _functionController <span class="token punctuation">.</span> stream <span class="token punctuation">.</span> <span class="token function">distinct</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> event <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span> event <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> start <span class="token punctuation">:</span> <span class="token function">_onStart</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> pause <span class="token punctuation">:</span> <span class="token function">_onPause</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> resume <span class="token punctuation">:</span> <span class="token function">_onResume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> reset <span class="token punctuation">:</span> <span class="token function">_onReset</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//ví dụ</span> <span class="token class-name">Button</span> <span class="token punctuation">(</span> onTap <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _functionController <span class="token punctuation">.</span> <span class="token function">add</span> <span class="token punctuation">(</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> resume <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> title <span class="token punctuation">:</span> <span class="token string">'Resume'</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> |
[Demo] Create your own flutter_bloc in Cubit style with Stream
- In order to increase data readability and divide the source code between the interface and the logic we need to separate the processing at the
Step 1: Create an abstract class to define the block’s basic variables and functions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">CustomCubit</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token class-name">CustomCubit</span> <span class="token punctuation">(</span> <span class="token class-name">T</span> initValue <span class="token punctuation">)</span> <span class="token punctuation">{</span> _streamCtrl <span class="token operator">=</span> <span class="token class-name">StreamController</span> <span class="token punctuation">.</span> <span class="token function">broadcast</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token function">add</span> <span class="token punctuation">(</span> initValue <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">//nếu dùng thêm thư viện rxdart thì xài seed để init value</span> <span class="token punctuation">}</span> late <span class="token class-name">StreamController</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> _streamCtrl <span class="token punctuation">;</span> <span class="token class-name">Stream</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> <span class="token keyword">get</span> stream <span class="token operator">=</span> <span class="token operator">></span> _streamCtrl <span class="token punctuation">.</span> stream <span class="token punctuation">;</span> <span class="token keyword">void</span> <span class="token function">emit</span> <span class="token punctuation">(</span> <span class="token class-name">T</span> state <span class="token punctuation">)</span> <span class="token punctuation">{</span> _streamCtrl <span class="token punctuation">.</span> <span class="token function">add</span> <span class="token punctuation">(</span> state <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _streamCtrl <span class="token punctuation">.</span> <span class="token function">close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
**_streamCtrl** = StreamController.broadcast()..add(initValue);
stream cannot receive this event because stream.listen is called after the constructor function runs.
You can initValue yourself in StreamBuilder or use the RxDart library that supports this function
</aside>
Step 2:
- Create TimerCubit
- Bring all declarations and functions into TimerCubit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | <span class="token keyword">class</span> <span class="token class-name">TimerCubit</span> <span class="token keyword">extends</span> <span class="token class-name">CustomCubit</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token class-name">TimerCubit</span> <span class="token punctuation">(</span> int initValue <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">super</span> <span class="token punctuation">(</span> initValue <span class="token punctuation">)</span> <span class="token punctuation">{</span> startTime <span class="token operator">=</span> initValue <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name">StreamSubscription</span> <span class="token operator">?</span> _subscription <span class="token punctuation">;</span> late <span class="token class-name">StreamSubscription</span> _controlSubscription <span class="token punctuation">;</span> <span class="token keyword">final</span> <span class="token class-name">StreamController</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">></span></span> _timerController <span class="token operator">=</span> <span class="token class-name">StreamController</span> <span class="token punctuation">.</span> <span class="token function">broadcast</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">Stream</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">></span></span> <span class="token keyword">get</span> timerControllerStream <span class="token operator">=</span> <span class="token operator">></span> _timerController <span class="token punctuation">.</span> stream <span class="token punctuation">;</span> int startTime <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token metadata symbol">@override</span> <span class="token keyword">void</span> <span class="token function">close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _subscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">cancel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> _controlSubscription <span class="token punctuation">.</span> <span class="token function">cancel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> _timerController <span class="token punctuation">.</span> <span class="token function">close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">init</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _controlSubscription <span class="token operator">=</span> _timerController <span class="token punctuation">.</span> stream <span class="token punctuation">.</span> <span class="token function">distinct</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> event <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span> event <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> start <span class="token punctuation">:</span> <span class="token function">_onStart</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> pause <span class="token punctuation">:</span> <span class="token function">_onPause</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> resume <span class="token punctuation">:</span> <span class="token function">_onResume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token class-name">CountDownEvent</span> <span class="token punctuation">.</span> reset <span class="token punctuation">:</span> <span class="token function">_onReset</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">break</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_setTime</span> <span class="token punctuation">(</span> int time <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">emit</span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onStart</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> _subscription <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">_onReset</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> _subscription <span class="token operator">=</span> <span class="token class-name">Stream</span> <span class="token punctuation">.</span> <span class="token function">periodic</span> <span class="token punctuation">(</span> <span class="token keyword">const</span> <span class="token class-name">Duration</span> <span class="token punctuation">(</span> seconds <span class="token punctuation">:</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> computationCount <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> startTime <span class="token operator">-</span> computationCount <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">_setTime</span> <span class="token punctuation">(</span> time <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> time <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">_onFinish</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onResume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> _subscription <span class="token operator">?</span> <span class="token punctuation">.</span> isPaused <span class="token operator">?</span> <span class="token operator">?</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _subscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">resume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onPause</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token punctuation">(</span> _subscription <span class="token operator">?</span> <span class="token punctuation">.</span> isPaused <span class="token operator">?</span> <span class="token operator">?</span> <span class="token boolean">true</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _subscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">pause</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onFinish</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _subscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">cancel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> _subscription <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">_onReset</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _subscription <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">cancel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> _subscription <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">timerController</span> <span class="token punctuation">(</span> <span class="token class-name">CountDownEvent</span> event <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timerController <span class="token punctuation">.</span> <span class="token function">add</span> <span class="token punctuation">(</span> event <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Step 3: Create BlocProvider
- Creating a BlocProvider to manage the block instance by context, if you don’t want to do it this way, you can create a global variable for your own management.
- BlocProvider is used from InheritedWidget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token comment">// final timerCubit = CustomBlocProvider.of<TimerCubit>(context);</span> <span class="token keyword">class</span> <span class="token class-name">CustomBlocProvider</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token keyword">extends</span> <span class="token class-name">CustomCubit</span> <span class="token punctuation">></span></span> <span class="token keyword">extends</span> <span class="token class-name">InheritedWidget</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token class-name">CustomBlocProvider</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> key <span class="token punctuation">,</span> required <span class="token keyword">this</span> <span class="token punctuation">.</span> bloc <span class="token punctuation">,</span> required <span class="token keyword">super</span> <span class="token punctuation">.</span> child <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">final</span> <span class="token class-name">T</span> bloc <span class="token punctuation">;</span> <span class="token keyword">static</span> <span class="token class-name">CustomBlocProvider</span> <span class="token operator">?</span> maybeOf <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token keyword">extends</span> <span class="token class-name">CustomCubit</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token class-name">BuildContext</span> context <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> context <span class="token punctuation">.</span> dependOnInheritedWidgetOfExactType <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">CustomBlocProvider</span> <span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token class-name">T</span> of <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token keyword">extends</span> <span class="token class-name">CustomCubit</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token class-name">BuildContext</span> context <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">final</span> <span class="token class-name">CustomBlocProvider</span> <span class="token operator">?</span> result <span class="token operator">=</span> maybeOf <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> context <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">assert</span> <span class="token punctuation">(</span> result <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> <span class="token string">'No BlocProvider found in context'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> result <span class="token operator">!</span> <span class="token punctuation">.</span> bloc <span class="token operator">as</span> <span class="token class-name">T</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token metadata symbol">@override</span> bool <span class="token function">updateShouldNotify</span> <span class="token punctuation">(</span> <span class="token class-name">CustomBlocProvider</span> oldWidget <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> bloc <span class="token operator">!=</span> oldWidget <span class="token punctuation">.</span> bloc <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">final</span> timerCubit <span class="token operator">=</span> context <span class="token punctuation">.</span> read <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">TimerCubit</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">extension</span> <span class="token class-name">ReadCustomBlocProviderOfContext</span> <span class="token keyword">on</span> <span class="token class-name">BuildContext</span> <span class="token punctuation">{</span> <span class="token class-name">T</span> read <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token keyword">extends</span> <span class="token class-name">CustomCubit</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token class-name">CustomBlocProvider</span> <span class="token punctuation">.</span> of <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">T</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Step 4: Declare
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <span class="token keyword">class</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token keyword">extends</span> <span class="token class-name">StatefulWidget</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token class-name">Key</span> <span class="token operator">?</span> key <span class="token punctuation">,</span> required <span class="token keyword">this</span> <span class="token punctuation">.</span> seconds <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">super</span> <span class="token punctuation">(</span> key <span class="token punctuation">:</span> key <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">final</span> int seconds <span class="token punctuation">;</span> <span class="token metadata symbol">@override</span> <span class="token class-name">State</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token punctuation">></span></span> <span class="token function">createState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token class-name">CountDownCustomCubitPageState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">CountDownCustomCubitPageState</span> <span class="token keyword">extends</span> <span class="token class-name">State</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">CountDownCustomCubitPage</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> late <span class="token class-name">TimerCubit</span> _timerCubit <span class="token punctuation">;</span> <span class="token metadata symbol">@override</span> <span class="token keyword">void</span> <span class="token function">initState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">initState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> _timerCubit <span class="token operator">=</span> <span class="token class-name">TimerCubit</span> <span class="token punctuation">(</span> widget <span class="token punctuation">.</span> seconds <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token function">init</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token metadata symbol">@override</span> <span class="token keyword">void</span> <span class="token function">dispose</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> _timerCubit <span class="token punctuation">.</span> <span class="token function">close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">dispose</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token metadata symbol">@override</span> <span class="token class-name">Widget</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token class-name">BuildContext</span> context <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token class-name">CustomBlocProvider</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">TimerCubit</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> bloc <span class="token punctuation">:</span> _timerCubit <span class="token punctuation">,</span> child <span class="token punctuation">:</span> <span class="token class-name">Scaffold</span> <span class="token punctuation">(</span> appBar <span class="token punctuation">:</span> <span class="token class-name">AppBar</span> <span class="token punctuation">(</span> title <span class="token punctuation">:</span> <span class="token class-name">Text</span> <span class="token punctuation">(</span> <span class="token string">"Timer test"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> body <span class="token punctuation">:</span> <span class="token class-name">Center</span> <span class="token punctuation">(</span> child <span class="token punctuation">:</span> <span class="token class-name">SingleChildScrollView</span> <span class="token punctuation">(</span> child <span class="token punctuation">:</span> <span class="token class-name">Column</span> <span class="token punctuation">(</span> children <span class="token punctuation">:</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Widget</span> <span class="token punctuation">></span></span> <span class="token punctuation">[</span> <span class="token function">_Content</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token comment">/*Some Code*/</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <span class="token keyword">class</span> _Content <span class="token keyword">extends</span> <span class="token class-name">StatelessWidget</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token function">_Content</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token class-name">Key</span> <span class="token operator">?</span> key <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">super</span> <span class="token punctuation">(</span> key <span class="token punctuation">:</span> key <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token metadata symbol">@override</span> <span class="token class-name">Widget</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token class-name">BuildContext</span> context <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">final</span> timerCubit <span class="token operator">=</span> context <span class="token punctuation">.</span> read <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">TimerCubit</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// final timerCubit = CustomBlocProvider.of<TimerCubit>(context);</span> <span class="token keyword">return</span> <span class="token class-name">StreamBuilder</span> <span class="token generics"><span class="token punctuation"><</span> int <span class="token punctuation">></span></span> <span class="token punctuation">(</span> initialData <span class="token punctuation">:</span> timerCubit <span class="token punctuation">.</span> startTime <span class="token punctuation">,</span> stream <span class="token punctuation">:</span> timerCubit <span class="token punctuation">.</span> stream <span class="token punctuation">,</span> builder <span class="token punctuation">:</span> <span class="token punctuation">(</span> context <span class="token punctuation">,</span> snapshot <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> snapshot <span class="token punctuation">.</span> hasData <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">final</span> int time <span class="token operator">=</span> snapshot <span class="token punctuation">.</span> data <span class="token operator">!</span> <span class="token punctuation">;</span> <span class="token keyword">var</span> separateWidget <span class="token operator">=</span> <span class="token class-name">Padding</span> <span class="token punctuation">(</span> padding <span class="token punctuation">:</span> <span class="token keyword">const</span> <span class="token class-name">EdgeInsets</span> <span class="token punctuation">.</span> <span class="token function">symmetric</span> <span class="token punctuation">(</span> horizontal <span class="token punctuation">:</span> <span class="token number">4</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> child <span class="token punctuation">:</span> <span class="token class-name">Text</span> <span class="token punctuation">(</span> <span class="token string">':'</span> <span class="token punctuation">,</span> style <span class="token punctuation">:</span> <span class="token class-name">Theme</span> <span class="token punctuation">.</span> <span class="token function">of</span> <span class="token punctuation">(</span> context <span class="token punctuation">)</span> <span class="token punctuation">.</span> textTheme <span class="token punctuation">.</span> headline2 <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">copyWith</span> <span class="token punctuation">(</span> fontFamily <span class="token punctuation">:</span> <span class="token string">'BlackOpsOne'</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> textAlign <span class="token punctuation">:</span> <span class="token class-name">TextAlign</span> <span class="token punctuation">.</span> center <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token class-name">FittedBox</span> <span class="token punctuation">(</span> child <span class="token punctuation">:</span> <span class="token class-name">InkWell</span> <span class="token punctuation">(</span> onTap <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> child <span class="token punctuation">:</span> <span class="token class-name">Row</span> <span class="token punctuation">(</span> mainAxisSize <span class="token punctuation">:</span> <span class="token class-name">MainAxisSize</span> <span class="token punctuation">.</span> min <span class="token punctuation">,</span> crossAxisAlignment <span class="token punctuation">:</span> <span class="token class-name">CrossAxisAlignment</span> <span class="token punctuation">.</span> center <span class="token punctuation">,</span> children <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> hour <span class="token punctuation">.</span> tens <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> hour <span class="token punctuation">.</span> ones <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> separateWidget <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> minute <span class="token punctuation">.</span> tens <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> minute <span class="token punctuation">.</span> ones <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> separateWidget <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> second <span class="token punctuation">.</span> tens <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">_TextWidget</span> <span class="token punctuation">(</span> number <span class="token punctuation">:</span> time <span class="token punctuation">.</span> second <span class="token punctuation">.</span> ones <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">const</span> <span class="token class-name">SizedBox</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
<aside> Full code → </aside>
Additional features available
- Can custom _Content to BlocBuilder
- Add features like buildWhen, listenner
- MultiBlocProvider
Reference
https://dart.dev/tutorials/language/streams
https://medium.flutterdevs.com/exploring-streambuilder-in-flutter-5958381bca67