本文共 8588 字,大约阅读时间需要 28 分钟。
dart flutter
The most important features of almost any app relies on the ability to interact with external API’s and databases. With that comes the problem of dealing with code that runs in an order different to how it was written while waiting for certain requests and operations to complete. We’re going to look into how Dart, particularly for Flutter, works with managing that complexity.
几乎所有应用程序的最重要功能都依赖于与外部API和数据库进行交互的能力。 随之而来的问题是,处理代码的顺序与等待某些请求和操作完成时的编写顺序不同。 我们将研究Dart(尤其是Flutter)如何管理这种复杂性。
Much of this may seem very familiar if you come from a front-end background, since Dart resembles JavaScript in a lot of ways. I’m going to assume that you have little to no knowledge of asynchronous concepts and techniques.
如果您来自前端背景,那么其中的许多内容可能看起来非常熟悉,因为Dart在很多方面都类似于JavaScript。 我将假设您几乎不了解异步概念和技术。
For our first example, I’m going to be using the , which will just return some basic information on whatever country we give it. This will also of course require the .
对于我们的第一个示例,我将使用 ,它将仅返回我们提供的任何国家的一些基本信息。 当然,这也需要 。
For our UI we’ll just use a centered button that will run our GetCountry
function.
对于我们的UI,我们将只使用一个将运行GetCountry
函数的居中按钮。
dependencies: flutter: sdk: flutter http: ^0.12.0+2
import 'package:flutter/material.dart';import 'package:http/http.dart' as http;import 'dart:convert'; //This allows us to convert the returned JSON data into something Dart can use.void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: MyHomePage(), ); }}class MyHomePage extends StatelessWidget { void GetCountry() async {} @override Widget build(BuildContext context) { return Scaffold( body: Center( child: MaterialButton( onPressed: () => GetCountry(), child: Container( color: Colors.blue, padding: EdgeInsets.all(15), child: Text('Get Country', style: TextStyle(color: Colors.white))), ), ), ); }}
While having every line in our code run in order is pretty straight forward to understand, that’s not always possible to achieve. When we send a request for information to an API, it’ll take some time before we get a response while our machine will be waiting for it to complete, halting things that may have nothing to do with the initial request. The problem is we don’t want our script to stop running every time something takes a while, but we also wouldn’t want it to run anything that relies on the return data prematurely, which could cause an error despite the request being successful.
尽管让我们的代码中的每一行按顺序运行很容易理解,但这并非总是可以实现的。 当我们向API发送信息请求时,我们将花一些时间才能得到响应,而我们的机器将等待响应完成,从而停止可能与初始请求无关的事情。 问题是我们不希望脚本每次花点时间都停止运行,但是我们也不希望脚本过早地运行依赖于返回数据的任何东西,尽管请求成功,但是这可能会导致错误。
The best of both worlds would be to set up our logic in a way that allows our machine to work ahead while waiting for a request to return while only letting code dependent on that request run when it’s available.
最好的办法是设置逻辑,使我们的机器在等待请求返回的同时继续工作,同时仅在依赖请求时才运行依赖于该请求的代码。
Our app’s data is most likely going to be in one of four forms, depending on whether or not they’re already available and whether or not they’re singular.
我们的应用程序数据很可能采用以下四种格式之一,具体取决于它们是否已经可用以及它们是否为单个。
You’re probably already very familiar with the standard strings and lists, futures and streams are the more interesting things that we’ll be exploring.
您可能已经非常熟悉标准字符串和列表,期货和数据流是我们将要探索的更有趣的事物。
Very similar to , Dart lets us chain methods together so we can easily pass the return data from one to the next and it even returns a promise-like data type, called futures. Futures are any singular type of data, like a string, which will be available later.
与非常相似,Dart使我们可以将方法链接在一起,这样我们就可以轻松地将返回数据从一个传递到另一个,甚至可以返回类似promise的数据类型,称为Future。 期货是任何奇异类型的数据,例如字符串,将在以后提供。
To use this technique, we just need to do whatever operations we need, like send a get request to REST Countries, then just chain .then
with our returned data passed-in as a parameter, use it however we want and/or we could keep chaining .then
forever. For error handling we can cap off our chain with a .catchError
and throw whatever was passed to it.
要使用此技术,我们只需要执行所需的任何操作,例如向REST国家/地区发送get请求,然后仅进行链接。然后将返回的数据作为参数传入,就可以.then
使用它,并且/或者我们可以保持链接.then
永远。 对于错误处理,我们可以使用.catchError
我们的链,并抛出传递给它的所有内容。
// Since we're returning a Future, we must set our function to type Future.Future GetCountry(country) { String countryUrl = 'https://restcountries.eu/rest/v2/name/$country'; http .get(countryUrl) .then((response) => jsonDecode(response.body)[0]['name']) .then((decoded) => print(decoded)) .catchError((error) => throw(error)); }// Update our Button to use our functionMaterialButton( onPressed: () => GetCountry('canada'), (...))
Try/CatchError definitely works well, but there’s also an alternative syntax that many find to be much for readable.
Try / CatchError确实可以很好地工作,但是还有一种替代语法,很多人认为它可读性强。
Async/Await works exactly the same , we use the async
keyword after our function name and add the await
keyword before anything that needs some time to run, like our get request. Now everything after it will be ran when a value has been returned. For error handling we can just throw the whole thing into a try/catch block.
Async / Await的工作原理与完全相同,我们在函数名称后使用async
关键字,并在需要一些时间才能运行的内容(例如我们的get请求)之前添加await
关键字。 现在,返回值后,它将执行所有后续操作。 对于错误处理,我们可以将整个内容放入try / catch块中。
Future GetCountry(country) async { String countryUrl = 'https://restcountries.eu/rest/v2/name/$country'; try { http.Response response = await http.get(countryUrl); Object decoded = jsonDecode(response.body)[0]['name']; print(decoded); } catch (e) { throw(e); }}
Something special with Dart is its use of streams for when we have many values being loaded asynchronously and instead of opening a connection once, like with our get request, we can make it stay open and ready for new data.
Dart的特殊之处在于,当我们有许多值被异步加载时,它可以使用流,而不是像get请求那样一次打开连接,我们可以使其保持打开状态并为新数据做好准备。
Since our example would get a bit too complicated by setting it up with a backend that allows streams, like or GraphQL, we’ll simulate a change in a chat application database by emitting a new ‘message’ every second.
由于我们的示例通过允许流的后端进行设置(例如或GraphQL)而变得有点复杂,因此我们将通过每秒发出一个新的“消息”来模拟聊天应用程序数据库中的更改。
We can create a simple stream with the StreamController
class, which works similarly to a List
, since it’s just a list of futures. We can control our stream with the properties on stream
, like listen
and close
to start and stop it.
我们可以使用StreamController
类创建一个简单的流,该类的工作方式类似于List
,因为它只是一个期货列表。 我们可以使用stream的属性来控制stream
,例如listen
和close
来启动和停止它。
It’s important to always use close() when your widget is removed. Streams will run continuously until they are shut off and will eat away at computing power even when the original widget is gone.
删除小部件时始终使用close()很重要。 流将一直运行,直到它们被关闭为止,并且即使原始窗口小部件消失了也会吞噬计算能力。
StreamControllerstreamController = StreamController(); void newMessage(int number, String message) { final duration = Duration(seconds: number); Timer.periodic(duration, (Timer t) => streamController.add(message)); } void initState() { super.initState(); streamController.stream.listen((messages) => print(messages)); newMessage(1, 'You got a message!'); } void dispose() { streamController.close(); super.dispose(); }
Standard streams can be a bit limited in that they only allow for one listener at a time. Instead we can use the broadcast
property on the StreamController
class to open up multiple channels.
标准流可能会有所限制,因为它们一次只允许一个侦听器。 相反,我们可以使用StreamController
类上的broadcast
属性来打开多个频道。
StreamControllerstreamController = StreamController.broadcast();void initState() { super.initState(); streamController.stream.listen((messages) => print('$messages First')); streamController.stream.listen((messages) => print('$messages Second')); newMessage(1, 'You got a message!');}
For me, working with asynchronous code was one of the hardest parts about learning programming and I hope I helped spare someone from any of the difficulty of understanding this strange style of code. Hopefully this short intro to asynchronous programming in Dart was helpful in your start to developing intelligent and dynamic apps.
对我来说,使用异步代码是学习编程最困难的部分之一,我希望我可以帮助人们摆脱理解这种奇怪代码风格的任何困难。 希望Dart异步编程的简短介绍对您开始开发智能和动态应用程序有所帮助。
翻译自:
dart flutter
转载地址:http://nphgb.baihongyu.com/