Flutter异步操作插件flutter_async的使用
Flutter 异步操作插件 flutter_async 的使用
Flutter Async
将传统的 Flutter 组件转换为异步版本,从而实现无缝处理异步操作。通过扩展熟悉的组件以支持异步功能,该包允许轻松执行后台任务、数据获取等操作,同时通过加载指示器提供反馈,并处理错误,而不会影响应用界面的响应性。
开始使用
可以选配地在应用的根部添加一个 Async
组件。这允许你配置或覆盖 flutter_async
的默认行为。你可以根据需求设置任意数量的 Async
组件。
return Async(
config: AsyncConfig(
loadingBuilder: (_) => CircularProgressIndicator(),
textButtonConfig: AsyncButtonConfig(
loadingBuilder: (_) => const Text('loading'),
),
),
child: // 你的应用主体
);
AsyncIndicator
AsyncIndicator
是一个智能的 CircularProgressIndicator
,它可以根据下方的颜色自动选择主色、次色或备用色。此外,它永远不会失真,可以叠加在其他组件上,并且当缩小时会线性插值笔画宽度。
AsyncIndicator()
// 或者通过扩展方法调用:
CircularProgressIndicator().asAsync()
这是 flutter_async
默认的 Async.loadingBuilder
。你可以像使用任何进度指示器一样使用它:
Builder(
builder: (context) {
if (isLoading) return AsyncIndicator();
return ... // 其他内容
}
)
AsyncBuilder
AsyncBuilder
是一个强大的组件,简化了在 Flutter 中处理 Future
和 Stream
对象。你无需定义任何构建器,flutter_async
会默认它们为 AsyncConfig
。
以下是 AsyncBuilder
的属性:
AsyncBuilder(
future: myFuture, // 或者 stream
noneBuilder: (context) {
// 当操作尚未开始时显示(例如,future 和 stream 为空)
return Text('none');
},
loadingBuilder: (context) {
return const CircularProgressIndicator(); // 默认为 AsyncIndicator()
},
reloadingBuilder: (context) {
// 在 `isLoading` 并且 `hasData` 或 `hasError` 时叠加显示
// 可以通过设置 `AsyncBuilder.skipReloading` 为 true 来跳过此加载器。
return const Align(alignment: Alignment.topCenter, child: LinearProgressIndicator());
},
errorBuilder: (context, error, stackTrace) {
return Text('$error');
},
builder: (context, data) {
return Text('$data');
},
)
对于简单的状态管理场景,可以使用 function
构造函数来处理异步函数:
AsyncBuilder.function(
future: () => myFutureFunction(), // 或者 stream
interval: Duration(seconds: 5), // 自动重载间隔
builder: (context, data) {
return TextButton(
child: Text('$data'),
onPressed: () => AsyncBuilder.of(context).reload(), // 手动重载
);
},
)
对于分页处理,可以使用 paged
构造函数:
AsyncBuilder.paged(
future: (page) async {
await Future.delayed(duration);
return List.generate(10, (i) => 'Item ${page * 10 + i}');
},
builder: (context, controller, list) {
return ListView.builder(
controller: controller,
itemCount: list.length,
itemBuilder: (context, index) {
return ListTile(title: Text(list[index]));
},
);
},
)
AsyncButton
只需在按钮前加上 Async
即可:
AsyncElevatedButton(
onPressed: onHello,
child: const Text('AsyncElevatedButton'),
),
或者使用 AsyncButtonExtension
,适用于任何 ButtonStyleButton
:
ElevatedButton(
onPressed: onHello,
child: const Text('ElevatedButton'),
).asAsync(),
可以通过以下方式程序化控制按钮:
AsyncButton.at(context).press();
AsyncButton.at(context).longPress();
AsyncButtonConfig 属性
/// 是否在状态变化时保持按钮高度。默认为 `true`。
final bool? keepHeight;
/// 是否在状态变化时保持按钮宽度。默认为 `false`。
final bool? keepWidth;
/// 此按钮是否应对其大小进行动画处理。
final bool? animateSize;
/// [AnimatedSize] 的配置。
final AnimatedSizeConfig? animatedSizeConfig;
/// 显示错误组件的时间。
final Duration? errorDuration;
/// 样式动画之间的持续时间。
final Duration? styleDuration;
/// 样式动画使用的曲线。
final Curve? styleCurve;
/// 加载时显示的组件。
final WidgetBuilder? loadingBuilder;
/// 错误时显示的组件。
final ErrorBuilder? errorBuilder;
未来计划和发展
该插件目前仍在开发中,我们计划在未来推出许多令人兴奋的新功能。我们正在不断努力改进和扩展我们的异步组件的功能。作为路线图的一部分,我们希望引入各种新的组件,提供更多灵活性和功能。
您的反馈对我们非常重要,我们鼓励您通过提出新功能、改进建议和报告错误来参与贡献。我们也欢迎开源社区的贡献。
敬请期待未来的更新,祝您编码愉快!
示例代码
import 'package:flutter/material.dart';
import 'package:flutter_async/flutter_async.dart';
void main() => runApp(
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
),
),
home: const Scaffold(
body: _MyWidget(),
),
),
);
class _MyWidget extends StatelessWidget {
const _MyWidget();
static const duration = Duration(seconds: 1);
static const fabPadding = EdgeInsets.all(8);
Future<void> onError() async {
await Future<void>.delayed(duration);
// ignore: strict_raw_type
throw ParallelWaitError<List, List>([], [
'Invalid user',
'The email is already in use',
'The password is too weak.',
]);
}
Future<void> onSuccess() async {
await Future<void>.delayed(duration);
}
[@override](/user/override)
Widget build(BuildContext context) {
const snapshot = AsyncSnapshot.withData(ConnectionState.done, 42);
if (snapshot.isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text(snapshot.error.toString()));
}
return Scaffold(
body: Row(
children: [
switch (const AsyncSnapshot<int>.nothing()) {
AsyncSnapshot(:final data?) => Center(child: Text(data.toString())),
AsyncSnapshot(:final error?) => Center(child: Text(error.toString())),
_ => const CircularProgressIndicator(),
},
Column(
children: [
AsyncButtonBuilder(
onPressed: onError,
child: const FlutterLogo(size: 120),
builder: (context, state, child) {
return InkWell(
onTap: state.press,
child: child,
);
},
),
ElevatedButton(
onPressed: onError,
child: const Text('ElevatedButton'),
).asAsync(),
ElevatedButton.icon(
onPressed: onError,
label: const Text('ElevatedButton.icon'),
icon: const Icon(Icons.add),
).asAsync(),
FilledButton(
onPressed: onError,
child: const Text('FilledButton'),
).asAsync(),
FilledButton.icon(
onPressed: onError,
label: const Text('FilledButton.icon'),
icon: const Icon(Icons.add),
).asAsync(),
FilledButton.tonal(
onPressed: onError,
child: const Text('FilledButton.tonal'),
).asAsync(),
FilledButton.tonalIcon(
onPressed: onError,
label: const Text('FilledButton.tonalIcon'),
icon: const Icon(Icons.add),
).asAsync(),
OutlinedButton(
onPressed: onError,
child: const Text('OutlinedButton'),
).asAsync(),
OutlinedButton.icon(
onPressed: onError,
label: const Text('OutlinedButton.icon'),
icon: const Icon(Icons.add),
).asAsync(),
TextButton(
onPressed: onError,
child: const Text('TextButton'),
).asAsync(),
TextButton.icon(
onPressed: onError,
label: const Text('TextButton.icon'),
icon: const Icon(Icons.add),
).asAsync(),
].map((e) => Expanded(child: Center(child: e))).toList(),
),
Column(
children: [
IconButton(
onPressed: onError,
icon: const Icon(Icons.add),
).asAsync(),
IconButton.filled(
onPressed: onSuccess,
icon: const Icon(Icons.add),
).asAsync(successIcon: const Icon(Icons.check)),
IconButton.filledTonal(
onPressed: onError,
icon: const Icon(Icons.add),
).asAsync(),
IconButton.outlined(
onPressed: onSuccess,
icon: const Icon(Icons.add),
).asAsync(),
],
),
SizedBox(
height: 400,
width: 400,
child: AsyncBuilder.paged(
future: (page) async {
await Future<void>.delayed(duration);
return List.generate(10, (i) => 'Patient ${page * 10 + i}');
},
builder: (context, controller, list) {
return ListView.builder(
controller: controller,
itemCount: list.length,
itemBuilder: (context, index) {
return ListTile(title: Text(list[index]));
},
);
},
),
),
],
),
// 使用 Async 作用域来配置其后代的 AsyncConfig。
floatingActionButton: Async(
config: AsyncConfig(
buttonConfig: AsyncButtonConfig.icon(
successIcon: const Icon(Icons.check),
successColor: Colors.green,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton.small(
onPressed: onSuccess,
child: const Icon(Icons.add),
).asAsync(),
FloatingActionButton(
onPressed: onSuccess,
isExtended: true,
child: const Icon(Icons.add),
).asAsync(),
FloatingActionButton.extended(
onPressed: onSuccess,
icon: const Icon(Icons.add),
label: const Text('extended'),
).asAsync(),
FloatingActionButton.large(
onPressed: onSuccess,
child: const Icon(Icons.add),
).asAsync(),
].map((e) => Padding(padding: fabPadding, child: e)).toList(),
),
),
);
}
}
更多关于Flutter异步操作插件flutter_async的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter异步操作插件flutter_async的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,处理异步操作通常涉及到与设备硬件、网络请求或其他需要耗时任务进行交互。flutter_async
并不是一个官方或广泛认知的插件,用于处理Flutter中的异步操作。Flutter社区中更常见的是使用 Dart 的原生异步功能(如 async
/await
关键字)和 Flutter 的其他官方插件来处理这些任务。
不过,为了展示如何在Flutter中处理异步操作,我将给出一个使用 Dart 的 async
/await
以及 http
插件(一个用于网络请求的官方插件)的示例。这将模拟一个异步的网络请求。
首先,确保在 pubspec.yaml
文件中添加了 http
依赖:
dependencies:
flutter:
sdk: flutter
http: ^0.13.3 # 确保使用最新版本
然后,运行 flutter pub get
来安装依赖。
接下来,编写一个 Flutter 应用,该应用将在按钮点击时发起一个网络请求,并在接收到响应后更新UI。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Async Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String responseData = '';
// 模拟一个异步的网络请求
Future<void> fetchData() async {
try {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
// 检查响应状态码
if (response.statusCode == 200) {
// 解析JSON数据
final jsonData = jsonDecode(response.body);
setState(() {
responseData = jsonData['title'].toString();
});
} else {
throw Exception('Failed to load data');
}
} catch (e) {
// 处理错误
setState(() {
responseData = 'Error: ${e.message}';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Async Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Response Data:',
style: TextStyle(fontSize: 20),
),
SizedBox(height: 10),
Text(
responseData,
style: TextStyle(fontSize: 24),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: fetchData,
child: Text('Fetch Data'),
),
],
),
),
);
}
}
在这个示例中,我们创建了一个简单的 Flutter 应用,该应用包含一个按钮和一个用于显示响应数据的文本区域。当用户点击按钮时,fetchData
函数会被调用,该函数使用 http.get
方法发起一个网络请求,并在请求成功后更新UI。
注意:
- 我们使用了
async
/await
来处理异步操作,这使得代码看起来更像是同步的,但实际上是异步执行的。 - 我们使用了
setState
方法来更新UI,这是Flutter中更新状态的标准方式。 - 错误处理是通过
try-catch
块实现的,这确保了即使在请求失败时,应用也不会崩溃,而是显示一个错误消息。
这个示例展示了如何在Flutter中处理异步操作,尽管没有直接使用名为 flutter_async
的插件,但原理是相通的。