บทที่ 22advanced|7 KB

บทที่ 22: Performance Optimization & Best Practices

บทที่ 22: Performance Optimization & Best Practices

🎯 เป้าหมายการเรียนรู้

หลังจากเรียนบทนี้แล้ว คุณจะสามารถ:

  • วิเคราะห์ประสิทธิภาพแอปด้วย Flutter DevTools (Profile Mode)
  • เข้าใจและแก้ไขปัญหา "Jank" (แอปกระตุก)
  • ใช้ const constructor เพื่อลดการ Build Widget ซ้ำซ้อน
  • จัดการ Memory Leak จาก Controller และ Stream
  • เพิ่มประสิทธิภาพ ListView ให้รองรับข้อมูลหลักหมื่นรายการ

📚 ทฤษฎีและแนวคิด

1. Build Phases

Flutter วาดหน้าจอเร็วมาก (60/120 fps) เพราะมันฉลาด

  1. Build: สร้าง Widget Tree (เร็วมาก, ทำบ่อย)
  2. Layout: คำนวณขนาดและตำแหน่ง (ช้ากว่า, ทำเมื่อจำเป็น)
  3. Paint: วาด pixel ลงจอ (ช้าสุด, ควรทำให้น้อยที่สุด)

2. Jank คืออะไร?

ถ้าเฟรมฮวบต่ำกว่า 60fps ผู้ใช้จะรู้สึก "กระตุก" (Jank) สาเหตุหลัก:

  • ทำคำนวณหนักๆ ใน Build method
  • Rebuild บ่อยเกินความจำเป็น
  • โหลดรูปภาพขนาดใหญ่เกินไป

💻 เทคนิคและวิธีการ (Best Practices)

1. ใช้ const ให้มากที่สุด

ทำไม? Widget ที่เป็น const จะถูกสร้างแค่ครั้งเดียวตอนเริ่มแอป และจะไม่ถูกสร้างใหม่เลยแม้ Parent จะ Rebuild

แย่ ❌:

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      Text("Hello"), // สร้างใหม่ทุกครั้งที่ build
      SizedBox(height: 10), // สร้างใหม่ทุกครั้ง
      MyCustomWidget(), // สร้างใหม่ทุกครั้ง
    ],
  );
}

ดี ✅:

@override
Widget build(BuildContext context) {
  return const Column( // const คลุมทั้งก้อน
    children: [
      Text("Hello"), // ตัวเดิม
      SizedBox(height: 10), // ตัวเดิม
      MyCustomWidget(), // ตัวเดิม
    ],
  );
}

2. ListView.builder (Lazy Loading)

ถ้ามีของเป็นร้อยชิ้น ห้ามใช้ ListView(children: [...]) หรือ Column เด็ดขาด เพราะมันจะสร้าง Widget เตรียมไว้ทั้งหมดทันที (Memory บวม)

ดี ✅:

ListView.builder(
  itemCount: 10000,
  itemBuilder: (context, index) {
    // สร้างเฉพาะตัวที่ "กำลังเห็น" บนหน้าจอ
    return ListTile(title: Text("Item $index"));
  },
)

3. Image Optimization (รูปภาพ)

รูปภาพ 4K กินแรมมหาศาล ถ้าเราจะโชว์แค่ Thumbnail 100x100px ให้ใช้ cacheWidth / cacheHeight

Image.network(
  "https://example.com/big_image.jpg",
  cacheWidth: 200, // resize ลงหน่วยความจำแค่ 200px
)

4. Controller & Stream ต้อง Dispose เสมอ

ถ้าไม่ dispose, ตัวแปรจะลอยค้างอยู่ใน RAM (Memory Leak) ยิ่งเปิดปิดหน้านั้นบ่อยๆ RAM ก็จะเต็มจนแอปเด้ง

class MyWidget extends StatefulWidget { ... }

class _MyWidgetState extends State<MyWidget> {
  late TextEditingController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController(); // สร้าง
  }

  @override
  void dispose() {
    _controller.dispose(); // ทำลาย
    super.dispose();
  }
}

5. RepaintBoundary

เหมาะสำหรับ Widget ที่มีการเปลี่ยนแปลงบ่อยๆ (เช่น Animation หมุนๆ, Video Player) แต่ Widget รอบข้างมักนิ่ง การหุ้มด้วย RepaintBoundary บอก Flutter ว่า "ตัวนี้วาดแยก Layer นะ อย่าไปกวนเพื่อน"

Column(
  children: [
    StaticHeader(), // ไม่ต้องวาดใหม่
    RepaintBoundary(
      child: RotatingSpinner(), // วาดใหม่เฉพาะในกรอบนี้
    ),
    StaticFooter(), // ไม่ต้องวาดใหม่
  ],
)

🛠 เครื่องมือตรวจสอบ (Tools)

1. Flutter DevTools

กดปุ่ม ⚡️ (Open DevTools) ใน VS Code หรือ Android Studio

  • Flutter Inspector: ดูโครงสร้าง Widget
  • Performance: ดูกราฟ FPS
  • Memory: ดูการใช้ RAM

2. Profile Mode

ห้ามวัดประสิทธิภาพใน Debug Mode เด็ดขาด! เพราะมันช้ากว่าความเป็นจริง 3-4 เท่า ให้รันด้วย:

flutter run --profile

📝 แบบฝึกหัด

โจทย์ที่ 1: Hunt for Const

สิ่งที่ต้องทำ:

  1. ติดตั้ง linter rule: prefer_const_constructors ใน analysis_options.yaml
  2. ไล่แก้ Warning สีฟ้าทั้งโปรเจกต์ให้เป็น const

โจทย์ที่ 2: Fix Memory Leak

สิ่งที่ต้องทำ:

  1. สร้างหน้าจอ Timer ที่นับเลขทุกวินาที (Timer.periodic)
  2. ลองกด Back ออก แล้วเข้ามาใหม่ 10 รอบ
  3. เปิด Log ดูว่า Timer เก่าหยุดทำงานไหม? (ถ้าไม่หยุด = Leak) -> แก้ไขโดย timer.cancel() ใน dispose()

📌 สรุปจบคอร์ส QUOM Learning

เดินทางมาถึงบทสุดท้าย ยินดีด้วยครับ! 🎉 คุณได้เรียนรู้ตั้งแต่พื้นฐาน จนถึงการทำ App จริงระดับ Production:

  1. Frontend: Flutter UI, State Management, Animation
  2. Backend: Node.js, Express, MongoDB
  3. Integration: API, Auth, Upload
  4. Advanced: i18n, Admin, Performance

Next Step: ไม่มีอะไรดีไปกว่าการ "ลงมือทำโปรเจกต์จริง" ขอให้สนุกกับการสร้างสรรค์แอปพลิเคชันครับ! 🚀


ไฟล์ที่เกี่ยวข้อง