We learned in the second grade of primary school:
Dart is single threaded and fluent depends on dart.
However, if we want to do some operations with a large amount of computation in the main thread, it will inevitably block the thread and make the UI update stuck or even stuck. Then what shall I do?
The good news is that Dart provides us with an isolate, which is similar to a thread. It is a thread in Dart.
The difference between an isolate and a thread is that memory is shared between threads, but not between an isolate and an isolate, so it is called an isolate.
In the flutter, the main thread is the main isolate. If we want to perform some operations with a large amount of computation, we should start a new isolate.
So how to open it? Before that, I want to tell a story.
The story of little red and little blue
There is a dancer named Xiao Hong. She is dancing to the audience
But the audience asked her to count how many even numbers are in a number while dancing. therefore...
That's OK! You must count while you jump. You can't stop when you count!
So little red had no choice but to call a little blue to help her calculate in the different world.
But little red and little blue are separated by the barriers of different worlds, and they don't have the same super power of thought. You can only send a package to Xiaolan when summoning.
Xiaolan receives the package after being called out. After opening it, it is the number to be calculated and starts to calculate. But how can she tell Xiaohong the result after calculation?
God made an agreement that when Xiaohong calls Xiaolan, a conveyor will be changed (the conveyor can be used to receive packages and generate an exclusive transmitter). Then send the transmitter to Xiaolan.
When Xiaolan is summoned, open the package. There is a transmitter inside. Then Xiaolan changes itself into a conveyor to generate a transmitter, and then sends Xiaolan's transmitter to Xiaohong with Xiaohong's transmitter. After sending out, sit next to the conveyor and wait for the package.
When Xiaohong receives Xiaolan's transmitter, she saves Xiaolan's transmitter.
When the audience asks Xiaohong to calculate, they are distracted and dance while generating a temporary conveyor. The number to be calculated and the temporary transmitter are packaged into a package, and then sent to Xiaolan through Xiaolan's transmitter, waiting for the conveyor to produce the result. Because you don't have to do it yourself, just wait, so the lines are smooth and the movements are beautiful when dancing.
Back to Xiaolan, Xiaolan sees a package on the conveyor, which is a temporary transmitter and a number. So Xiao Lan began to calculate. After calculation, use the temporary transmitter to send the number to Xiaohong.
After receiving the result, Xiao Hong tells the audience how many even numbers that number has.
At the end of the story, I tried this style for the first time. It may be a little bad, but it should be very easy to understand in combination with the code.
Code practice
First, let's let Xiao Hong dance.
@override void initState() { controller = AnimationController(duration: Duration(seconds: 3), vsync: this); animation = Tween<double>(begin: 0, end: pi * 2).animate(controller); controller.repeat(); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ AnimatedBuilder( animation: animation, child: Text( 'Xiao Hong', style: TextStyle(fontSize: 30, color: Colors.red), ), builder: (context, child) { return Transform.rotate( angle: animation.value, child: child, ); }), ], ), ), ); }
Next, let Xiao Hong calculate how many even numbers there are in a number.
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ AnimatedBuilder( animation: animation, child: Text( 'Xiao Hong', style: TextStyle(fontSize: 30, color: Colors.red), ), builder: (context, child) { return Transform.rotate( angle: animation.value, child: child, ); }), Padding( padding: EdgeInsets.only(top: 16), child: RaisedButton(onPressed: count, child: Text('Asynchronously calculate the number of even numbers')), ), Text(result) ], ), ), ); } int getRandom() { int a = Random().nextInt(100); return a + 1000000000; } // Asynchronous computing count() async { int random = getRandom(); int r = countEven(random); setState(() { this.result = '${random.toString()}yes ${r.toString()}Even number'; }); } //Calculate the number of even numbers int countEven(num num) { int count = 0; while (num > 0) { if (num % 2 == 0) { count++; } num--; } return count; }
This is the effect
Define isolate
I'd call it summoning little blue.
First, we need to know two classes:
ReceivePort SendPort
ReceivePort is the transmitter in the story, and SendPort is the transmitter.
We can create the conveyor and the corresponding transmitter in the following ways
ReceivePort receive = ReceivePort(); SendPort sender = receive.sendPort;
OK, just know that. Next, we define little blue.
// Message package, used to store temporary senders and messages class MessagePackage { SendPort sender; // Temporary transmitter dynamic msg; // news MessagePackage(this.sender, this.msg); } // I'm Xiao Lan. I'm responsible for calculating the number of even numbers. I must be a top-level function blueCounter(SendPort redSendPort) { // Create a conveyor for little blue ReceivePort blueReceivePort = ReceivePort(); // Use the little red transmitter to send the little blue transmitter redSendPort.send(blueReceivePort.sendPort); // Monitor Xiaolan's conveyor and wait for Xiaohong to call Xiaolan for calculation blueReceivePort.listen((package) { // msg here is dynamic and needs to be converted into MessagePackage class, which is the package encapsulation class defined above MessagePackage _msg = package as MessagePackage; // Xiaolan starts to calculate int r = countEven(_msg.msg as num); // After calculation, use Xiaohong's temporary transmitter to tell Xiaohong _msg.sender.send(r); }); }
Create isolate
The tool man Xiaolan has been defined. Let's initialize (summon) Xiaolan.
// Create isolate void createIsolate() async { // Create a small red receiver to receive a small blue transmitter ReceivePort redReceive = ReceivePort(); // Create an isolate and pass Xiaohong's transmitter to Xiaolan isolate = await Isolate.spawn<SendPort>(blueCounter, redReceive.sendPort); // Wait for Xiaolan to send the transmitter to Xiaohong blueSender = await redReceive.first; // No, remember to turn off the receiver redReceive.close(); } @override void initState() { controller = AnimationController(duration: Duration(seconds: 3), vsync: this); animation = Tween<double>(begin: 0, end: pi * 2).animate(controller); controller.repeat(); // Initialize isolate in initState createIsolate(); super.initState(); }
Now Xiaolan has been summoned and has established communication with Xiaohong.
Start isolate calculation
Next, let's let Xiao Hong start calculating.
@override Widget build(BuildContext context) { ... Padding( padding: EdgeInsets.only(top: 16), child: RaisedButton( onPressed: isolateCount, child: Text('isolate Calculate the number of even numbers') ), ), ... } // Enable isolate calculation isolateCount() async { // Gets the number to calculate int random = getRandom(); // Create a temporary conveyor ReceivePort _temp = ReceivePort(); // Send a message package with the small blue transmitter, which is the transmitter of the temporary conveyor and the number to be calculated blueSender.send(MessagePackage(_temp.sendPort, random)); // Wait for the temporary conveyor to return the calculation result int r = await _temp.first; // No, remember to turn off the temporary receiver _temp.close(); // Tell the audience the results of the calculation setState(() { this.result = '${random.toString()}yes ${r.toString()}Even number'; }); }
It should be noted that when you finish using the isolate, remember to destroy it.
@override void dispose() { // Destroy isolate isolate?.kill(priority: Isolate.immediate); super.dispose(); }
OK, here I believe you have understood and can use isolate.
Let's take a look at the renderings.
Using computed
It's not over yet. Maybe you'll find it too troublesome. Yes, it's too troublesome to use isolate. Isolate is designed to input and output multiple times, and we only have one input and output for this calculation, so we can complete the calculation operation with the computed provided by fluent, which is a package of isolate. Let's see how to use it! Knock simple.
import 'dart:isolate'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'dart:math'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'isolate Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'isolate Demo'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { AnimationController controller; Animation<double> animation; String result = ''; SendPort blueSender; Isolate isolate; @override void initState() { controller = AnimationController(duration: Duration(seconds: 3), vsync: this); animation = Tween<double>(begin: 0, end: pi * 2).animate(controller); controller.repeat(); // Initialize isolate in initState createIsolate(); super.initState(); } @override void dispose() { // Destroy isolate isolate?.kill(priority: Isolate.immediate); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ AnimatedBuilder( animation: animation, child: Text( 'Xiao Hong', style: TextStyle(fontSize: 30, color: Colors.red), ), builder: (context, child) { return Transform.rotate( angle: animation.value, child: child, ); }), Padding( padding: EdgeInsets.only(top: 16), child: RaisedButton(onPressed: count, child: Text('Asynchronously calculate the number of even numbers')), ), Padding( padding: EdgeInsets.only(top: 16), child: RaisedButton( onPressed: isolateCount, child: Text('isolate Calculate the number of even numbers')), ), Padding( padding: EdgeInsets.only(top: 16), child: RaisedButton( onPressed: computeCount, child: Text('compute Calculate the number of even numbers')), ), Text(result) ], ), ), ); } // Get random number int getRandom() { int a = Random().nextInt(100); return a + 1000000000; } // Asynchronous computing count() async { int random = getRandom(); int r = countEven(random); setState(() { this.result = '${random.toString()}yes ${r.toString()}Even number'; }); } // Create isolate void createIsolate() async { // Create a small red receiver to receive a small blue transmitter ReceivePort redReceive = ReceivePort(); // Create an isolate and pass Xiaohong's transmitter to Xiaolan isolate = await Isolate.spawn<SendPort>(blueCounter, redReceive.sendPort); // Wait for Xiaolan to send the transmitter to Xiaohong blueSender = await redReceive.first; // No, remember to turn off the receiver redReceive.close(); } // Calculate with compute computeCount() async { int random = getRandom(); // The callback function of compute must be a top-level function or static function int r = await compute(countEven, random); setState(() { this.result = '${random.toString()}yes ${r.toString()}Even number'; }); } // Enable isolate calculation isolateCount() async { // Gets the number to calculate int random = getRandom(); // Create a temporary conveyor ReceivePort _temp = ReceivePort(); // Send a message package with the small blue transmitter, which is the transmitter of the temporary conveyor and the number to be calculated blueSender.send(MessagePackage(_temp.sendPort, random)); // Wait for the temporary conveyor to return the calculation result int r = await _temp.first; _temp.close(); // Tell the audience the results of the calculation setState(() { this.result = '${random.toString()}yes ${r.toString()}Even number'; }); } } // Message package, used to store temporary senders and messages class MessagePackage { SendPort sender; // Temporary transmitter dynamic msg; // news MessagePackage(this.sender, this.msg); } // I'm Xiao Lan. I'm responsible for calculating the number of even numbers. I must be a top-level function blueCounter(SendPort redSendPort) { // Create a conveyor for little blue ReceivePort blueReceivePort = ReceivePort(); // Use the little red transmitter to send the little blue transmitter redSendPort.send(blueReceivePort.sendPort); // Monitor Xiaolan's conveyor and wait for Xiaohong to call Xiaolan for calculation blueReceivePort.listen((package) { // msg here is dynamic and needs to be converted into MessagePackage class, which is the package encapsulation class defined above MessagePackage _msg = package as MessagePackage; // Xiaolan starts to calculate int r = countEven(_msg.msg as num); // After calculation, use Xiaohong's temporary transmitter to tell Xiaohong _msg.sender.send(r); }); } //Calculate the number of even numbers. This function requires a lot of computing resources and time int countEven(num num) { int count = 0; while (num > 0) { if (num % 2 == 0) { count++; } num--; } return count; }
Author: seven point red panda
Link: https://www.jianshu.com/p/27646ea6bcd1
Source: Jianshu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.