Menu
CoddyTech
flag Ar iconالعربيةdown icon

التنظيف باستخدام 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، فسيظل الزر معطّلًا إلى الأبد.

challenge icon

التحدي

متوسط

احفظ مع ترك الحقل فارغًا: سيظهر الخطأ، وسيظل 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)),
          ],
        ),
      ),
    );
  }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البيانات والشبكة

تدرّب بنفسك: مترجم Flutter عبر الإنترنت