التنظيف باستخدام finally
جزء من قسم البيانات والشبكة في رحلة Flutter على Coddy. الدرس 12 من 27.
هناك بعض الأعمال التي يجب تنفيذها سواء نجح الاستدعاء أم فشل: إخفاء مؤشر التحميل، وإعادة تفعيل زر. من السهل نسيان كتابتها في أحد الموضعين عند كتابتها في كلٍّ من try وcatch. لدى Dart كتلة ثالثة لهذا الغرض، وهي finally:
try {
await saveName(name);
} catch (e) {
// أظهر الخطأ
} finally {
// يُنفَّذ دائمًا: بعد try أو بعد catch
}تُنفَّذ finally أخيرًا في كل مرة: بعد try عندما ينجح، وبعد catch عندما يفشل. وهذا يجعلها الموضع الوحيد للتراجع عمّا أعددته قبل الاستدعاء.
هنا يعطّل التطبيق زر حفظ أثناء الحفظ، باستخدام onPressed: saving ? null : save. لا يمكن الضغط على زر تكون قيمة onPressed فيه null. إذا لم تعد قيمة saving إلى false، فسيظل الزر معطّلًا إلى الأبد.
التحدي
متوسطاحفظ مع ترك الحقل فارغًا: سيظهر الخطأ، وسيظل 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)),
],
),
),
);
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البيانات والشبكة
3عندما تفشل الاستدعاءات
التقاط الأخطاء باستخدام tryإطلاق خطأالتنظيف باستخدام finallyحالة الخطأ في FutureBuilderزر للمحاولة مجددًاتدرّب بنفسك: مترجم Flutter عبر الإنترنت