Очистка с помощью finally
Часть раздела Данные и сеть путешествия по Flutter на Coddy. Урок 12 из 27.
Некоторые действия нужно выполнить независимо от того, завершился вызов успешно или с ошибкой: скрыть индикатор загрузки, снова включить кнопку. Легко забыть написать этот код в одном из блоков — try или catch. В Dart для этого есть третий блок — finally:
try {
await saveName(name);
} catch (e) {
// показать ошибку
} finally {
// выполняется всегда: после try или после catch
}finally выполняется последним каждый раз: после try, если вызов завершился успешно, или после catch, если он завершился с ошибкой. Поэтому это единственное место, где можно отменить то, что вы настроили перед вызовом.
Здесь приложение делает кнопку Save неактивной во время сохранения с помощью onPressed: saving ? null : save. Нажать кнопку, у которой onPressed равен null, нельзя. Если saving так и не вернётся к значению false, кнопка навсегда останется неактивной.
Задание
СреднеНажмите Save, когда поле пустое: появится ошибка, а кнопка Save останется серой, поэтому вы не сможете попробовать снова. Перенесите saving = false из блока try в блок finally, поместив его в отдельный вызов setState.
Попробуйте сами
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: NameScreen(),
);
}
}
class NameScreen extends StatefulWidget {
const NameScreen({super.key});
@override
State<NameScreen> createState() => _NameScreenState();
}
class _NameScreenState extends State<NameScreen> {
final controller = TextEditingController();
String status = '';
bool saving = false;
@override
void dispose() {
controller.dispose();
super.dispose();
}
Future<void> saveName(String name) async {
await Future.delayed(const Duration(seconds: 1));
if (name.isEmpty) {
throw Exception('The name cannot be empty');
}
}
Future<void> save() async {
setState(() {
saving = true;
});
try {
await saveName(controller.text);
setState(() {
status = 'Saved: ${controller.text}';
saving = false;
});
} catch (e) {
setState(() {
status = '$e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: controller,
decoration: const InputDecoration(labelText: 'Name'),
),
const SizedBox(height: 16),
ElevatedButton(onPressed: saving ? null : save, child: const Text('Save')),
const SizedBox(height: 16),
Text(status, style: const TextStyle(fontSize: 18)),
],
),
),
);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Данные и сеть
1Future (асинхронные результаты)
Значение, которое появится позжеОжидание с async и awaitФункции, возвращающие FutureПрактический API Coddy3Когда вызовы завершаются ошибкой
Перехват ошибок с помощью tryВыбрасывание ошибкиОчистка с помощью finallyСостояние ошибки в FutureBuilderКнопка «Попробовать снова»Потренируйтесь самостоятельно: Онлайн-компилятор Flutter