أدوات تطوير Flutter
مقدمة إلى أدوات تطوير Flutter
أدوات تطوير Flutter (DevTools) هي مجموعة من أدوات التصحيح وتحليل الأداء القوية المصممة خصيصاً لتطبيقات Flutter و Dart. تعمل في متصفح الويب وتتصل بتطبيق Flutter قيد التشغيل مما يمنحك رؤية عميقة لشجرة الودجات والأداء واستخدام الذاكرة وطلبات الشبكة والمزيد.
DevTools جزء أساسي من أدوات كل مطور Flutter. سواء كنت تصحح مشكلة تخطيط أو تتبع تسرب ذاكرة أو تحسن أداء التطبيق توفر DevTools التصور والبيانات التي تحتاجها.
فتح DevTools
هناك عدة طرق لتشغيل أدوات تطوير Flutter حسب بيئة التطوير:
من الطرفية
فتح DevTools عبر الطرفية
# عند تشغيل التطبيق بـ flutter run اضغط v
flutter run
# التطبيق يبدأ...
# اضغط: v (يفتح DevTools في المتصفح)
# أو شغل DevTools مباشرة
dart devtools
# أو افتح DevTools واتصل بعنوان محدد
dart devtools --connect http://127.0.0.1:9100
من VS Code
مع تثبيت إضافة Flutter يمكنك فتح DevTools مباشرة من المحرر:
- افتح لوحة الأوامر (
Ctrl+Shift+PأوCmd+Shift+P) - اكتب “Flutter: Open DevTools” واخترها
- أو انقر أيقونة DevTools في شريط الحالة أثناء التصحيح
من Android Studio
Android Studio لديه DevTools مدمجة في بيئة التطوير:
- شغل تطبيق Flutter في وضع التصحيح
- اذهب إلى View > Tool Windows > Flutter Inspector
- أو انقر زر “Open DevTools” في لوحة Flutter Inspector
مفتش الودجات
مفتش الودجات هو الأداة الأكثر استخداماً في DevTools. يسمح لك باستكشاف شجرة الودجات وفحص خصائص الودجات وفهم سلوك التخطيط.
عرض شجرة الودجات
تعرض شجرة الودجات كل ودجت في تطبيقك في عرض هرمي. يمكنك توسيع وطي العقد للتنقل في الهيكل الشجري.
مثال شجرة ودجات في المفتش
MaterialApp
├── Scaffold
│ ├── AppBar
│ │ └── Text ('تطبيقي')
│ ├── Center
│ │ └── Column
│ │ ├── Text ('مرحباً')
│ │ ├── SizedBox (height: 16)
│ │ └── ElevatedButton
│ │ └── Text ('انقر هنا')
│ └── FloatingActionButton
│ └── Icon (Icons.add)
عند تحديد ودجت في الشجرة تعرض اللوحة اليمنى خصائصها بما في ذلك:
- خصائص الودجت: المعاملات الممررة للمُنشئ
- خصائص كائن العرض: الحجم والموضع والقيود وتفاصيل الرسم
- معلومات التخطيط: عوامل المرونة والمحاذاة والحشو والهوامش
تحديد الودجات على الجهاز
إحدى أكثر الميزات فائدة هي القدرة على تحديد ودجت مباشرة على جهازك أو المحاكي وجعل DevTools تحددها في شجرة الودجات.
وضع تحديد الودجت
# تفعيل وضع تحديد الودجت:
# 1. في DevTools انقر زر "Select Widget Mode"
# (أيقونة المؤشر مع التقاطع في شريط الأدوات العلوي)
# 2. انقر أي ودجت على جهازك/المحاكي
# 3. DevTools تنتقل لتلك الودجت في الشجرة
# 4. تُحدد الودجت بطبقة زرقاء على الجهاز
# من الطرفية أثناء التشغيل:
# اضغط: s (يبدل وضع تحديد الودجت)
مستكشف التخطيط
مستكشف التخطيط أداة مرئية ضمن مفتش الودجات تساعدك على فهم تخطيطات Flex (Row و Column و Flex). يعرض مخططاً لكيفية ترتيب أبناء flex وخصائصهم.
تصحيح تخطيط Row
// إذا كان هذا التخطيط لا يعمل كما هو متوقع...
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(flex: 2, child: Text('يسار')),
Expanded(flex: 1, child: Text('يمين')),
],
)
// حدد Row في مفتش الودجات
// يعرض مستكشف التخطيط:
// - اتجاه المحور الرئيسي والمحاذاة
// - محاذاة المحور المتقاطع
// - عامل المرونة والحجم الفعلي لكل ابن
// - المساحة المتاحة مقابل المستخدمة
يعرض مستكشف التخطيط:
- اتجاه المحور الرئيسي (أفقي لـ Row وعمودي لـ Column)
- تصور محاذاة المحور الرئيسي
- تصور محاذاة المحور المتقاطع
- عامل المرونة والحجم المحسوب لكل ابن
- توزيع المساحة الحرة
عرض الأداء
يساعدك عرض الأداء على تحديد وإصلاح مشاكل الأداء في تطبيق Flutter. يعرض أوقات عرض الإطارات ويساعد في اكتشاف التأتأة (إطارات مسقطة) ويوفر تتبعات زمنية.
فهم أوقات الإطارات
أهداف الأداء
# يستهدف Flutter 60 إطار في الثانية (FPS)
# ميزانية كل إطار: 16.67 مللي ثانية (1000ms / 60)
# تقسيم الإطار:
# - مرحلة البناء: إنشاء شجرة الودجات
# - مرحلة التخطيط: حساب الأحجام والمواضع
# - مرحلة الرسم: رسم البكسلات على الشاشة
# - التركيب: تجميع الطبقات لوحدة GPU
# شريط أخضر = إطار مُعالج ضمن الميزانية (< 16.67ms)
# شريط أحمر = إطار تجاوز الميزانية (تأتأة/إطار مسقط)
# شريط أزرق = وقت خيط واجهة المستخدم
# شريط أخضر = وقت خيط التحويل
تحديد التأتأة
تحدث التأتأة عندما يستغرق إطار أكثر من 16.67 مللي ثانية للعرض. يحدد عرض الأداء هذه الإطارات بالأحمر لتتمكن من تحديدها والتحقيق فيها.
أسباب شائعة للتأتأة
// سيء: بناء ودجات مكلفة في كل إطار
@override
Widget build(BuildContext context) {
// هذا يرتب قائمة كبيرة في كل إعادة بناء
final sorted = myLargeList.toList()..sort();
return ListView.builder(
itemCount: sorted.length,
itemBuilder: (ctx, i) => Text(sorted[i]),
);
}
// جيد: تخزين القائمة المرتبة وإعادة الحساب عند الحاجة فقط
List<String>? _cachedSorted;
@override
Widget build(BuildContext context) {
_cachedSorted ??= myLargeList.toList()..sort();
return ListView.builder(
itemCount: _cachedSorted!.length,
itemBuilder: (ctx, i) => Text(_cachedSorted![i]),
);
}
flutter run --profile) وليس وضع التصحيح. وضع التصحيح يتضمن فحوصات وتأكيدات إضافية تبطئ العرض بشكل ملحوظ. قياسات الأداء في وضع التصحيح لا تمثل الأداء الحقيقي.عرض الذاكرة
يساعدك عرض الذاكرة على فهم وتحسين استخدام ذاكرة تطبيقك. يعرض تخصيص الكومة وأحداث جمع القمامة ويسمح لك بأخذ لقطات ذاكرة.
مفاهيم الذاكرة الرئيسية
ميزات عرض الذاكرة
# يعرض عرض الذاكرة:
# 1. مخطط استخدام الذاكرة بمرور الوقت
# - استخدام الكومة (منطقة زرقاء)
# - الذاكرة الخارجية (منطقة خضراء)
# - RSS (الحجم المقيم الإجمالي - إجمالي الذاكرة)
# 2. تتبع التخصيص
# - أي الفئات يتم تخصيصها
# - كم نسخة من كل فئة
# - إجمالي البايتات المستهلكة
# 3. أحداث جمع القمامة (GC)
# - متى يعمل GC (خطوط عمودية على المخطط)
# - كم ذاكرة تم تحريرها
# 4. لقطات الذاكرة
# - خذ لقطة لرؤية جميع الكائنات الحية
# - قارن اللقطات لإيجاد تسربات الذاكرة
اكتشاف تسربات الذاكرة
يحدث تسرب الذاكرة عندما تبقى الكائنات في الذاكرة رغم عدم الحاجة إليها. الأسباب الشائعة في Flutter تشمل:
- عدم التخلص من المتحكمات (
TextEditingControllerوAnimationControllerوScrollController) - عدم إلغاء اشتراكات التدفقات
- الاحتفاظ بمراجع لودجات تم التخلص منها
- المراجع الدائرية التي تمنع جمع القمامة
تنظيف الموارد بشكل صحيح
class _MyPageState extends State<MyPage> {
late TextEditingController _textController;
late ScrollController _scrollController;
@override
void initState() {
super.initState();
_textController = TextEditingController();
_scrollController = ScrollController();
}
@override
void dispose() {
// تخلص دائماً من المتحكمات لمنع تسربات الذاكرة
_textController.dispose();
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
controller: _scrollController,
children: [
TextField(controller: _textController),
],
),
);
}
}
عرض الشبكة
يعرض عرض الشبكة جميع طلبات HTTP التي يجريها تطبيقك. هذا لا يُقدر بثمن لتصحيح استدعاءات API والتحقق من أوقات الاستجابة والتحقق من بيانات الطلب/الاستجابة.
معلومات عرض الشبكة
# لكل طلب شبكة يمكنك رؤية:
# - العنوان وطريقة HTTP (GET, POST, PUT, DELETE)
# - رمز الحالة (200, 404, 500, إلخ.)
# - رؤوس الطلب والجسم
# - رؤوس الاستجابة والجسم
# - التوقيت (بحث DNS والاتصال و TLS ووقت الاستجابة)
# - حجم الطلب وحجم الاستجابة
# مثال: تصحيح استدعاء API فاشل
# 1. افتح عرض الشبكة في DevTools
# 2. شغل استدعاء API في تطبيقك
# 3. اعثر على الطلب في القائمة
# 4. تحقق من رمز الحالة وجسم الاستجابة
# 5. تحقق من رؤوس الطلب (Authorization, Content-Type)
عرض السجلات
يعرض عرض السجلات رسائل السجل من تطبيقك بما في ذلك أحداث الإطار وأحداث جمع القمامة ورسائل السجل المخصصة.
إضافة سجلات لتطبيقك
import 'dart:developer' as developer;
// تسجيل بسيط
developer.log('المستخدم نقر الزر');
// تسجيل باسم (فئة)
developer.log(
'استجابة API: 200 OK',
name: 'NetworkService',
);
// تسجيل مع تفاصيل الخطأ
developer.log(
'فشل في جلب البيانات',
name: 'NetworkService',
error: 'انتهاء مهلة الاتصال بعد 30 ثانية',
level: 1000, // مستوى الخطورة
);
// طباعة التصحيح (تظهر أيضاً في عرض السجلات)
debugPrint('تمت إعادة بناء الودجت في \${DateTime.now()}');
developer.log() بدلاً من print() للتسجيل بجودة إنتاجية. دالة developer.log() تدعم التسجيل المنظم بأسماء ومستويات وكائنات أخطاء وتتكامل مباشرة مع DevTools.تصحيح مشاكل التخطيط
مشاكل التخطيط من أكثر المشاكل شيوعاً التي يواجهها مطورو Flutter. توفر DevTools عدة أدوات لتشخيصها:
طلاء التصحيح
تفعيل طلاء التصحيح
# من الطرفية أثناء تشغيل التطبيق:
# اضغط: p (يبدل طلاء التصحيح)
# أو برمجياً:
import 'package:flutter/rendering.dart';
debugPaintSizeEnabled = true;
# طلاء التصحيح يعرض:
# - خطوط زرقاء: حدود الودجات
# - أسهم خضراء: الحشو
# - مناطق زرقاء داكنة: مساحة المحاذاة
# - أسهم صفراء: الهوامش
أخطاء التخطيط الشائعة
تصحيح خطأ التجاوز
// خطأ: A RenderFlex overflowed by 42 pixels on the right
// يحدث عندما يتجاوز الأبناء المساحة المتاحة للأب
// سيء: أبناء Row أعرض مما يجب
Row(
children: [
Text('هذا نص طويل جداً يتجاوز ودجت الصف'),
Icon(Icons.arrow_forward),
],
)
// إصلاح: غلف النص في Expanded أو Flexible
Row(
children: [
Expanded(
child: Text(
'هذا نص طويل جداً يلتف الآن بشكل صحيح',
overflow: TextOverflow.ellipsis,
),
),
Icon(Icons.arrow_forward),
],
)
تصحيح خطأ الارتفاع غير المحدود
// خطأ: Vertical viewport was given unbounded height
// يحدث عندما لا يكون لودجت قابلة للتمرير قيد ارتفاع
// سيء: ListView داخل Column بدون قيود
Column(
children: [
Text('الرأس'),
ListView( // خطأ! ListView يحتاج ارتفاعاً محدوداً
children: [Text('عنصر 1'), Text('عنصر 2')],
),
],
)
// إصلاح: غلف ListView في Expanded
Column(
children: [
Text('الرأس'),
Expanded(
child: ListView(
children: [Text('عنصر 1'), Text('عنصر 2')],
),
),
],
)
فحص خصائص الودجات
عند تحديد ودجت في مفتش الودجات تعرض لوحة التفاصيل جميع خصائصها. هذا مفيد للغاية لفهم لماذا تبدو أو تتصرف ودجت بطريقة معينة.
مثال فحص الخصائص
// حدد Container في مفتش الودجات لترى:
Container(
width: 200,
height: 100,
margin: EdgeInsets.all(16),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
boxShadow: [BoxShadow(blurRadius: 4, color: Colors.grey)],
),
child: Text('مرحباً'),
)
// DevTools تعرض:
// - القيود: BoxConstraints(w=200, h=100)
// - الحجم: Size(200, 100)
// - الهامش: EdgeInsets(16, 16, 16, 16)
// - الحشو: EdgeInsets(24, 12, 24, 12)
// - تفاصيل الزخرفة (اللون ونصف قطر الحدود والظلال)
جلسة تصحيح عملية
دعنا نمر عبر جلسة تصحيح كاملة باستخدام DevTools لإصلاح مشكلة تخطيط حقيقية.
الخطوة 1: التخطيط المعطل
class ProfileCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
child: Row(
children: [
CircleAvatar(radius: 30, child: Icon(Icons.person)),
Column(
children: [
Text('محمد أحمد', style: TextStyle(fontSize: 18)),
Text('mohammed@example.com'),
Text('مطور Flutter أول في شركة التقنية الدولية'),
],
),
Icon(Icons.chevron_right),
],
),
);
}
}
الخطوة 2: استخدام DevTools للتشخيص
# 1. افتح مفتش ودجات DevTools
# 2. حدد ودجت Row
# 3. مستكشف التخطيط يعرض: الأبناء تتجاوز العرض المتاح
# 4. ودجات نص Column لها عرض غير مقيد
# 5. الحل: غلف Column في Expanded
الخطوة 3: التخطيط المصلح
class ProfileCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: EdgeInsets.all(12),
child: Row(
children: [
CircleAvatar(radius: 30, child: Icon(Icons.person)),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('محمد أحمد', style: TextStyle(fontSize: 18)),
Text('mohammed@example.com'),
Text(
'مطور Flutter أول في شركة التقنية الدولية',
overflow: TextOverflow.ellipsis,
),
],
),
),
Icon(Icons.chevron_right),
],
),
),
);
}
}
ملخص
في هذا الدرس تعلمت:
- كيفية فتح أدوات تطوير Flutter من الطرفية و VS Code و Android Studio
- استخدام مفتش الودجات لاستكشاف شجرة الودجات وفحص الخصائص
- مستكشف التخطيط لتصحيح تخطيطات Flex (Row و Column)
- تحديد الودجات مباشرة على الجهاز لإيجادها في الشجرة
- عرض الأداء لتحديد إسقاط الإطارات والتأتأة
- عرض الذاكرة لاكتشاف تسربات الذاكرة وتتبع التخصيصات
- عرض الشبكة لتصحيح طلبات HTTP واستدعاءات API
- عرض السجلات للسجلات المنظمة للتطبيق
- تقنيات عملية لتصحيح مشاكل التخطيط الشائعة
تمرين عملي
ابنِ تطبيقاً بسيطاً فيه ListView داخل Column (مما سيسبب خطأ تخطيط). استخدم أدوات تطوير Flutter لـ: (1) تحديد الخطأ في مفتش الودجات، (2) استخدام مستكشف التخطيط لفهم مشكلة القيود، (3) إصلاح التخطيط بتغليف ListView في ودجت Expanded، (4) أخذ لقطة ذاكرة قبل وبعد تمرير القائمة. تدرب أيضاً على استخدام وضع تحديد الودجت لتحديد ودجات معينة على الشاشة.