Menu
CoddyTech

التنظيف باستخدام 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 عبر الإنترنت