FutureBuilder هو عنصر واجهة في Flutter يعيد بناء واجهته تلقائياً بناءً على الحالة الحالية لـ AsyncSnapshot المستلمة من Future المُمرَّر. على عكس الاستدعاء اليدوي لـ setState بعد await، يوفر FutureBuilder نهجاً تصريحياً: فهو يشترك في Future عند أول عرض ويستدعي دالة builder عند كل تغيير في الحالة — تحميل، خطأ أو بيانات جاهزة. وفقاً لمرجع Flutter API (2026)، FutureBuilder مفيد بشكل خاص لتحميل البيانات من الشبكة، القراءة من قاعدة البيانات وأي عمليات غير متزامنة حيث يجب أن تعرض واجهة المستخدم مؤشر تحميل أو رسالة خطأ أو محتوى جاهز.
النقاط الرئيسية
FutureBuilder هو عنصر واجهة مدمج في Flutter من حزمة widgets يأخذ Future
على عكس StreamBuilder الذي يعمل مع تدفقات البيانات (Stream)، FutureBuilder مصمم للعمليات غير المتزامنة لمرة واحدة: طلب HTTP، قراءة ملف، استعلام قاعدة بيانات. FutureBuilder يدير الاشتراك في Future بنفسه: عند البناء الأول، يبدأ Future ويتتبع اكتماله. عندما يتم تدمير العنصر، لا يلغي FutureBuilder الـ Future — هذه مسؤولية المطور.
وفقاً لـ Flutter Cookbook (2026)، يُوصى باستخدام FutureBuilder للحالات التي تُنفذ فيها عملية غير متزامنة مرة واحدة عند تهيئة الشاشة. للعمليات المتكررة أو تدفقات البيانات، استخدم StreamBuilder. كلا العنصرين يتبعان نفس نمط واجهة المستخدم التفاعلية، لكن FutureBuilder محسّن للطلبات لمرة واحدة.
التنفيذ الداخلي لـ FutureBuilder يشترك في Future باستخدام Future.then و catchError. عند بدء FutureBuilder، يضبط connectionState على ConnectionState.waiting ويستدعي builder ببيانات فارغة. عند الاكتمال بنجاح، يتغير connectionState إلى ConnectionState.done مع البيانات. عند الخطأ، يمتلئ snapshot.error بكائن الخطأ. كل تغيير يؤدي إلى إعادة بناء العنصر.
AsyncSnapshot هو كائن حاوية يمرره FutureBuilder إلى دالة builder عند كل تغيير حالة. يحتوي على كل المعلومات حول الحالة الحالية للعملية غير المتزامنة: هل التحميل قيد التقدم، ما البيانات المستلمة، أو هل حدث خطأ. فهم AsyncSnapshot هو مفتاح بناء واجهة المستخدم بشكل صحيح مع FutureBuilder.
| الخاصية | النوع | الوصف |
|---|---|---|
| connectionState | ConnectionState | حالة الاتصال الحالية (none, waiting, active, done) |
| data | T? | البيانات المستلمة من Future (null حتى الاكتمال أو عند الخطأ) |
| error | Object? | كائن الخطأ إذا اكتمل Future باستثناء |
| hasData | bool | true إذا كانت data ليست null و connectionState هي ConnectionState.done |
| hasError | bool | true إذا اكتمل Future بخطأ |
التعداد ConnectionState يحدد مرحلة العملية غير المتزامنة. None — الحالة الأولية عندما لم يبدأ Future بعد (نادر الاستخدام، عادة في البناء الأول بدون initialData). Waiting — Future قيد التنفيذ، البيانات لم تستلم بعد. Active — يُستخدم فقط بواسطة StreamBuilder للتدفقات ذات البيانات الجزئية. Done — اكتمل Future، البيانات متاحة عبر snapshot.data أو الخطأ عبر snapshot.error.
المعالجة الصحيحة لجميع حالات AsyncSnapshot في دالة builder هي شرط إلزامي لكود الإنتاج. إذا لم يتم معالجة حالة waiting، سيرى المستخدم شاشة فارغة أثناء التحميل. إذا لم يتم معالجة hasError، سيتلقى المستخدم استثناءً بدون شرح. النمط الموصى به: تحقق من hasError → تحقق من hasData → عرض التحميل افتراضياً.
FutureBuilder يمكن استخدامه بعدة أنماط قياسية، كل منها يحل مهمة محددة. دعنا ننظر إلى السيناريوهات الرئيسية: تحميل البيانات عند التهيئة، التحميل مع التخزين المؤقت، الطلبات المتوازية ومعالجة الأخطاء مع إعادة المحاولة.
النمط الأكثر شيوعاً — FutureBuilder في دالة build لـ StatefulWidget أو StatelessWidget. يتم تمرير Future من initState أو إنشاؤه مباشرة في build. من المهم عدم إنشاء Future في دالة build عند كل إعادة بناء — سيؤدي ذلك إلى طلبات متكررة. استخدم Future مخزناً في حقل State.
لمنع الطلبات المتكررة، يمكن دمج FutureBuilder مع CachedNetworkImage أو ذاكرة تخزين مؤقت محلية. بعد التحميل الأول، تُحفظ البيانات في الذاكرة أو SharedPreferences، ويعرض FutureBuilder البيانات المخزنة مؤقتاً فورياً مع تحديثها من الشبكة بالتوازي. هذا يحسن تجربة المستخدم من خلال الاستجابة الفورية.
وفقاً لـ pub.dev (2026)، التخزين المؤقت مهم بشكل خاص للصور وقوائم البيانات. FutureBuilder مع CachedNetworkImageProvider يعرض تلقائياً الصورة المخزنة مؤقتاً، وعند غيابها — مؤشر تحميل يليه عرض الملف الذي تم تنزيله.
FutureBuilder وإدارة الحالة اليدوية عبر setState هما نهجان لواجهة المستخدم غير المتزامنة في Flutter. لكل منهما مزاياه وقيوده. يعتمد الاختيار على تعقيد الشاشة وعدد العمليات غير المتزامنة.
FutureBuilder يتفوق في البساطة: لا تحتاج لإعلان حقول لحالة التحميل والبيانات والخطأ — كل شيء يُدار عبر AsyncSnapshot. إنه مثالي للشاشات البسيطة بعملية غير متزامنة واحدة (طلب HTTP واحد، قراءة قاعدة بيانات). ومع ذلك، مع 5+ عمليات غير متزامنة على شاشة واحدة، يُنشئ FutureBuilder تداخلاً مفرطاً — مما ينتج “هرماً” من FutureBuilders المتداخلة.
setState مع أعلام الحالة اليدوية يعطي تحكماً أكبر وقابلية قراءة أفضل للوغاريتمات المعقدة. للشاشات ذات الطلبات المتعددة والمترابطة (تحميل مستخدم → تحميل طلباته → تحميل تفاصيل الطلب)، من الأفضل استخدام setState مع ChangeNotifier أو Bloc. وفقاً لدليل إدارة حالة Flutter (2026)، للسيناريوهات المعقدة يُوصى باستخدام Riverpod أو Bloc بدلاً من FutureBuilder، حيث أنها توفر فصلاً أفضل بين المنطق والعرض.
لنفكر في مثال عملي لـ FutureBuilder لتحميل قائمة مستخدمين من REST API. يوضح الكود المعالجة الصحيحة لحالات AsyncSnapshot الثلاث: التحميل والخطأ والبيانات الجاهزة.
class UserListPage extends StatefulWidget {
const UserListPage({super.key});
@override
State<UserListPage> createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
final Future<List<User>> usersFuture = UserRepository().fetchUsers();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('المستخدمين')),
body: FutureBuilder<List<User>>(
future: usersFuture,
builder: (context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasError) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 48, color: Colors.red),
const SizedBox(height: 16),
Text('خطأ: ${snapshot.error}'),
],
),
);
}
if (snapshot.hasData) {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(backgroundImage: NetworkImage(users[index].avatarUrl)),
title: Text(users[index].name),
subtitle: Text(users[index].email),
);
},
);
}
return const Center(child: CircularProgressIndicator());
},
),
);
}
}
في المثال، FutureBuilder يعالج الحالات الثلاث. عند الخطأ، يتم عرض أيقونة مع رسالة خطأ. عند التحميل الناجح — ListView مع الصور الرمزية والأسماء. أثناء التحميل — CircularProgressIndicator. يُعلن Future كحقل فئة، مما يمنع الاستدعاء المتكرر عند إعادة البناء. هذا النمط يغطي 90% من سيناريوهات استخدام FutureBuilder في تطبيقات الجوال.
الأسئلة الشائعة
FutureBuilder يستدعي builder عند كل تغيير في حالة Future: المرة الأولى عند الإنشاء (connectionState: none أو waiting)، والمرة الثانية عند الاكتمال (connectionState: done). إذا أعيد بناء العنصر الأب، فسيتم إعادة بناء FutureBuilder أيضاً. لمنع الاستدعاءات المتكررة، تأكد من إنشاء Future خارج دالة build — وإلا فإن كل استدعاء لـ build سيُنشئ Future جديد.
خزّن Future في حقل StatefulWidget (في initState) أو استخدم التخزين المؤقت للاستدعاءات. إذا تم إنشاء Future داخل دالة build، فكل استدعاء لـ build سيُنشئ Future جديداً، وسيعيد FutureBuilder تشغيل العملية غير المتزامنة. لـ StatelessWidget، استخدم حزمة cached_future أو عناصر keep-alive بحيث يتم تنفيذ Future مرة واحدة بغض النظر عن إعادة البناء.
FutureBuilder مصمم للعمليات غير المتزامنة لمرة واحدة (طلب HTTP واحد، قراءة قاعدة بيانات واحدة). StreamBuilder يعمل مع تدفقات البيانات التي يمكنها إصدار قيم متعددة بمرور الوقت (دردشة، تحديثات الأسعار، تحديد الموقع الجغرافي). StreamBuilder يدعم ConnectionState.active للبيانات الجزئية، بينما FutureBuilder يدعم فقط waiting و done.
لعدة Futures متوازية، استخدم Future.wait ومرر النتيجة إلى FutureBuilder واحد. Future.wait يأخذ قائمة من Futures ويعيد Future — عندما تكتمل جميع Futures، يتلقى builder مصفوفة من النتائج. للطلبات المتسلسلة، استخدم سلسلة Future.then داخل Future واحد أو FutureBuilders متداخلة (أقل قابلية للقراءة). البديل هو حزمة riverpod مع AsyncValue لحالات غير متزامنة متعددة.
FutureBuilder لا يلغي Future تلقائياً. للإلغاء، استخدم CancelableOperation من حزمة async أو آلية مخصصة عبر علامة cancelled في State. ضع العلامة في dispose()، وتحقق منها بعد اكتمال Future قبل استدعاء setState. بديلاً، استخدم حزمة riverpod مع AutoDispose التي تلغي تلقائياً العمليات غير المتزامنة عند الخروج من الشاشة.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.