20 āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™ Flutter āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ”āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļēāđāļ­āļ›āļĄāļ·āļ­āļ–āļ·āļ­

āđ€āļ•āļĢāļĩāļĒāļĄāļ•āļąāļ§āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™ Flutter āļ”āđ‰āļ§āļĒāļ„āļģāļ–āļēāļĄ 20 āļ‚āđ‰āļ­āļ—āļĩāđˆāļ–āļđāļāļ–āļēāļĄāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ” āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄ Widget, State Management, Dart, āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄ āđāļĨāļ°āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ” āļžāļĢāđ‰āļ­āļĄāļ„āļģāļ­āļ˜āļīāļšāļēāļĒāļ­āļĒāđˆāļēāļ‡āļĨāļ°āđ€āļ­āļĩāļĒāļ”āđāļĨāļ°āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™ Flutter āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļēāđāļ­āļ›āļĄāļ·āļ­āļ–āļ·āļ­

āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™ Flutter āļˆāļ°āļ›āļĢāļ°āđ€āļĄāļīāļ™āļ„āļ§āļēāļĄāđ€āļŠāļĩāđˆāļĒāļ§āļŠāļēāļāđƒāļ™ Framework, āļ āļēāļĐāļē Dart āđāļĨāļ°āļĢāļđāļ›āđāļšāļšāļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄāđāļ­āļ›āļĄāļ·āļ­āļ–āļ·āļ­ āļšāļ—āļ„āļ§āļēāļĄāļ™āļĩāđ‰āļĢāļ§āļšāļĢāļ§āļĄ 20 āļ„āļģāļ–āļēāļĄāļ—āļĩāđˆāļ–āļđāļāļ–āļēāļĄāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ” āļ•āļąāđ‰āļ‡āđāļ•āđˆāļžāļ·āđ‰āļ™āļāļēāļ™āđ„āļ›āļˆāļ™āļ–āļķāļ‡āđāļ™āļ§āļ„āļīāļ”āļ‚āļąāđ‰āļ™āļŠāļđāļ‡ āļžāļĢāđ‰āļ­āļĄāļ„āļģāļ•āļ­āļšāļ­āļĒāđˆāļēāļ‡āļĨāļ°āđ€āļ­āļĩāļĒāļ”āđāļĨāļ°āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āļ—āļĩāđˆāđƒāļŠāđ‰āļ‡āļēāļ™āđ„āļ”āđ‰āļˆāļĢāļīāļ‡

āđ€āļ„āļĨāđ‡āļ”āļĨāļąāļšāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

āļœāļđāđ‰āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļˆāļ°āđƒāļŦāđ‰āļ„āļ°āđāļ™āļ™āļŠāļđāļ‡āļāļąāļšāļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāļ—āļĩāđˆāļŠāļēāļĄāļēāļĢāļ–āļ­āļ˜āļīāļšāļēāļĒ "āđ€āļŦāļ•āļļāļœāļĨ" āļ„āļ§āļšāļ„āļđāđˆāļāļąāļš "āļ§āļīāļ˜āļĩāļāļēāļĢ" āđ„āļ”āđ‰ āļŠāļģāļŦāļĢāļąāļšāđāļ•āđˆāļĨāļ°āđāļ™āļ§āļ„āļīāļ” āļāļēāļĢāđ€āļ‚āđ‰āļēāđƒāļˆāļāļĢāļ“āļĩāļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āđāļĨāļ°āļ‚āđ‰āļ­āđāļĨāļāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļ—āļēāļ‡āđ€āļ—āļ„āļ™āļīāļ„āļˆāļ°āđ€āļ›āđ‡āļ™āļ•āļąāļ§āļ•āļąāļ”āļŠāļīāļ™āļ—āļĩāđˆāļŠāļģāļ„āļąāļ

āļ„āļģāļ–āļēāļĄāļžāļ·āđ‰āļ™āļāļēāļ™ Flutter āđāļĨāļ° Dart

1. StatelessWidget āđāļĨāļ° StatefulWidget āđāļ•āļāļ•āđˆāļēāļ‡āļāļąāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

StatelessWidget āđ€āļ›āđ‡āļ™ Widget āļ—āļĩāđˆāđ„āļĄāđˆāļŠāļēāļĄāļēāļĢāļ–āđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđ„āļ”āđ‰ (immutable) āļ‹āļķāđˆāļ‡āļĢāļđāļ›āļĨāļąāļāļĐāļ“āđŒāļ‚āļķāđ‰āļ™āļ­āļĒāļđāđˆāļāļąāļšāļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āļ—āļĩāđˆāļāļģāļŦāļ™āļ”āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™ āđ€āļĄāļ·āđˆāļ­āļŠāļĢāđ‰āļēāļ‡āđāļĨāđ‰āļ§āļˆāļ°āđ„āļĄāđˆāļĄāļĩāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđƒāļ” āđ† āļŠāđˆāļ§āļ™ StatefulWidget āļˆāļ°āđ€āļāđ‡āļš State āļ—āļĩāđˆāļŠāļēāļĄāļēāļĢāļ–āđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđ„āļ”āđ‰āļ•āļēāļĄāđ€āļ§āļĨāļē āđāļĨāļ°āļ—āļģāđƒāļŦāđ‰ Widget āļ–āļđāļ Rebuild āđƒāļŦāļĄāđˆ

stateless_example.dartdart
// StatelessWidget: static display, no change after construction
class WelcomeMessage extends StatelessWidget {
  // Final parameter - never changes
  final String username;

  const WelcomeMessage({super.key, required this.username});

  
  Widget build(BuildContext context) {
    // Build called once (unless parent rebuilds)
    return Text('Welcome, $username');
  }
}
stateful_example.dartdart
// StatefulWidget: mutable state, can rebuild itself
class LikeButton extends StatefulWidget {
  const LikeButton({super.key});

  
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  // Mutable local state
  int _likeCount = 0;

  void _incrementLike() {
    // setState triggers rebuild with new state
    setState(() {
      _likeCount++;
    });
  }

  
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _incrementLike,
      child: Text('Likes: $_likeCount'),
    );
  }
}

āļŦāļĨāļąāļāļāļēāļĢāļ„āļ·āļ­ āđƒāļŦāđ‰āđƒāļŠāđ‰ StatelessWidget āđ€āļ›āđ‡āļ™āļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ āđāļĨāļ°āđƒāļŠāđ‰ StatefulWidget āđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­āļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āļˆāļąāļ”āļāļēāļĢ State āļ āļēāļĒāđƒāļ™ Widget āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™

2. Widget Tree āđƒāļ™ Flutter āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Flutter āļˆāļąāļ”āļĢāļ°āđ€āļšāļĩāļĒāļš Interface āđ‚āļ”āļĒāđāļšāđˆāļ‡āđ€āļ›āđ‡āļ™ 3 Tree āļ—āļĩāđˆāđ€āļŠāļ·āđˆāļ­āļĄāđ‚āļĒāļ‡āļāļąāļ™ āđ„āļ”āđ‰āđāļāđˆ Widget Tree (āļāļēāļĢāļ›āļĢāļ°āļāļēāļĻāđāļšāļš immutable), Element Tree (Lifecycle āđāļĨāļ° Binding) āđāļĨāļ° Render Tree (Layout āđāļĨāļ° Painting)

widget_tree_example.dartdart
// Declarative structure - widgets describe the UI
class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    // Each widget creates an Element in the Element Tree
    return MaterialApp(
      home: Scaffold(
        // Scaffold creates multiple RenderObjects
        body: Center(
          // Center modifies its child's layout
          child: Column(
            children: [
              // Each Text has its own RenderParagraph
              Text('First'),
              Text('Second'),
            ],
          ),
        ),
      ),
    );
  }
}

āđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāđ€āļĢāļĩāļĒāļ setState Flutter āļˆāļ°āđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļš Widget Tree āđ€āļāđˆāļēāđāļĨāļ°āđƒāļŦāļĄāđˆāđ€āļžāļ·āđˆāļ­ Rebuild āđ€āļ‰āļžāļēāļ° Element āļ—āļĩāđˆāļĄāļĩāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡ āļāļĢāļ°āļšāļ§āļ™āļāļēāļĢ Differentiation āļ™āļĩāđ‰āļ­āļēāļĻāļąāļĒ Key āđāļĨāļ°āļ›āļĢāļ°āđ€āļ āļ—āļ‚āļ­āļ‡ Widget

3. Const Constructor āļ„āļ·āļ­āļ­āļ°āđ„āļĢ āđāļĨāļ°āļ—āļģāđ„āļĄāļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰?

Const Constructor āļŠāļĢāđ‰āļēāļ‡ Widget āđƒāļ™āļ‚āļąāđ‰āļ™āļ•āļ­āļ™ Compile Time āđāļ—āļ™āļ—āļĩāđˆāļˆāļ°āđ€āļ›āđ‡āļ™ Runtime āļ—āļģāđƒāļŦāđ‰ Flutter āļŠāļēāļĄāļēāļĢāļ–āļ™āļģ Instance āđ€āļ”āļīāļĄāļāļĨāļąāļšāļĄāļēāđƒāļŠāđ‰āļ‹āđ‰āļģāđ„āļ”āđ‰ āļ‹āļķāđˆāļ‡āļŠāđˆāļ§āļĒāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđ‚āļ”āļĒāļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢ Rebuild āļ—āļĩāđˆāđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™

const_example.dartdart
class OptimizedScreen extends StatelessWidget {
  const OptimizedScreen({super.key});

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        // ✅ const: same instance reused on each build
        const Icon(Icons.star, size: 48),
        const SizedBox(height: 16),
        const Text('Static title'),

        // ❌ Non-const: new instance on each build
        Icon(Icons.star, color: Theme.of(context).primaryColor),
      ],
    );
  }
}

// Custom widget with const constructor
class StaticCard extends StatelessWidget {
  final String title;

  // All fields must be final for const
  const StaticCard({super.key, required this.title});

  
  Widget build(BuildContext context) {
    return Card(child: Text(title));
  }
}

Flutter Analyzer āļˆāļ°āđāļˆāđ‰āļ‡āđ€āļ•āļ·āļ­āļ™āđ€āļĄāļ·āđˆāļ­āļĄāļĩāđ‚āļ­āļāļēāļŠāđƒāļŠāđ‰ const āđāļ•āđˆāđ„āļĄāđˆāđ„āļ”āđ‰āđƒāļŠāđ‰āļœāđˆāļēāļ™ lint rule prefer_const_constructors

4. āļ­āļ˜āļīāļšāļēāļĒāļ›āļĢāļ°āđ€āļ āļ—āļ•āđˆāļēāļ‡ āđ† āļ‚āļ­āļ‡ Key āđƒāļ™ Flutter

Key āļ—āļģāļŦāļ™āđ‰āļēāļ—āļĩāđˆāļĢāļąāļāļĐāļē State āļ‚āļ­āļ‡ Widget āđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāļˆāļąāļ”āđ€āļĢāļĩāļĒāļ‡āđƒāļŦāļĄāđˆ āļŦāļēāļāđ„āļĄāđˆāļĄāļĩ Key Flutter āļˆāļ°āļ­āļēāļĻāļąāļĒāļ•āļģāđāļŦāļ™āđˆāļ‡āđƒāļ™ Tree āļ‹āļķāđˆāļ‡āļ­āļēāļˆāļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ” Bug āđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļĨāļģāļ”āļąāļšāļ‚āļ­āļ‡āļĢāļēāļĒāļāļēāļĢ

keys_example.dartdart
class TodoList extends StatelessWidget {
  final List<Todo> todos;

  const TodoList({super.key, required this.todos});

  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: todos.length,
      itemBuilder: (context, index) {
        final todo = todos[index];
        // ✅ ValueKey: preserves state if order changes
        return TodoTile(
          key: ValueKey(todo.id),
          todo: todo,
        );
      },
    );
  }
}

// Different key types for different contexts
class KeyExamples extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        // ValueKey: based on a unique value
        Container(key: ValueKey('unique-id')),

        // ObjectKey: based on object identity
        Container(key: ObjectKey(myObject)),

        // UniqueKey: new key on each build
        Container(key: UniqueKey()),

        // GlobalKey: access state from outside
        Form(key: _formKey),
      ],
    );
  }
}

GlobalKey āļĒāļąāļ‡āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļŠāļēāļĄāļēāļĢāļ–āđ€āļ‚āđ‰āļēāļ–āļķāļ‡ State āļ‚āļ­āļ‡ Widget āļˆāļēāļāļ āļēāļĒāļ™āļ­āļāđ„āļ”āđ‰ āđāļ•āđˆāļ„āļ§āļĢāđƒāļŠāđ‰āļ­āļĒāđˆāļēāļ‡āļĢāļ°āļĄāļąāļ”āļĢāļ°āļ§āļąāļ‡

āļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļš Dart

5. final āđāļĨāļ° const āđƒāļ™ Dart āļ•āđˆāļēāļ‡āļāļąāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

final āļāļģāļŦāļ™āļ”āļ•āļąāļ§āđāļ›āļĢāļ—āļĩāđˆāļŠāļēāļĄāļēāļĢāļ–āļāļģāļŦāļ™āļ”āļ„āđˆāļēāđ„āļ”āđ‰āđ€āļžāļĩāļĒāļ‡āļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§ āđ‚āļ”āļĒāļ›āļĢāļ°āđ€āļĄāļīāļ™āļ„āđˆāļēāđƒāļ™āļ‚āļ“āļ° Runtime āļŠāđˆāļ§āļ™ const āļŠāļĢāđ‰āļēāļ‡āļ„āđˆāļēāļ„āļ‡āļ—āļĩāđˆāđƒāļ™āļ‚āļąāđ‰āļ™āļ•āļ­āļ™ Compile Time āļ‹āļķāđˆāļ‡āđ€āļ›āđ‡āļ™ Immutable āđāļĨāļ°āļ–āļđāļāļ›āļĢāļ°āđ€āļĄāļīāļ™āļ„āđˆāļēāļāđˆāļ­āļ™āļāļēāļĢāļĢāļąāļ™

final_const_example.dartdart
class DateExample {
  // final: value assigned at runtime
  final DateTime createdAt = DateTime.now();

  // const: value known at compile time
  static const int maxItems = 100;
  static const String appName = 'MyApp';

  // ❌ Error: DateTime.now() not const (runtime value)
  // static const DateTime timestamp = DateTime.now();
}

void demonstrateDifference() {
  // final: each call can have different value
  final timestamp1 = DateTime.now();
  final timestamp2 = DateTime.now();
  print(timestamp1 == timestamp2); // false (different)

  // const: same instance reused
  const list1 = [1, 2, 3];
  const list2 = [1, 2, 3];
  print(identical(list1, list2)); // true (same instance)
}

āđƒāļ™ Flutter āļ„āļ§āļĢāđƒāļŠāđ‰ const āļŠāļģāļŦāļĢāļąāļš Widget āļ—āļĩāđˆāđ€āļ›āđ‡āļ™ Static āđāļĨāļ°āđƒāļŠāđ‰ final āļŠāļģāļŦāļĢāļąāļšāļ„āđˆāļēāļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļ„āļģāļ™āļ§āļ“

6. Future āđāļĨāļ° async/await āļ—āļģāļ‡āļēāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Future āđāļ—āļ™āļ„āđˆāļēāļ—āļĩāđˆāļˆāļ°āļžāļĢāđ‰āļ­āļĄāđƒāļŠāđ‰āļ‡āļēāļ™āđƒāļ™āļ āļēāļĒāļŦāļĨāļąāļ‡ āļŠāđˆāļ§āļ™ async/await āļ—āļģāđƒāļŦāđ‰āđ„āļ§āļĒāļēāļāļĢāļ“āđŒāļ­āđˆāļēāļ™āļ‡āđˆāļēāļĒāļ‚āļķāđ‰āļ™āđƒāļ™āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļāļąāļš Asynchronous Operation āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļ‹āđ‰āļ­āļ™ Callback

async_example.dartdart
class UserRepository {
  final ApiClient _client;

  UserRepository(this._client);

  // Future: promise of a future value
  Future<User> fetchUser(String id) async {
    try {
      // await suspends execution until resolution
      final response = await _client.get('/users/$id');
      return User.fromJson(response);
    } catch (e) {
      // Errors propagate normally with async/await
      throw UserNotFoundException(id);
    }
  }

  // Parallel execution with Future.wait
  Future<List<User>> fetchUsers(List<String> ids) async {
    // All requests start simultaneously
    final futures = ids.map((id) => fetchUser(id));
    // Wait for all to complete
    return Future.wait(futures);
  }

  // Sequential processing
  Future<void> processSequentially(List<String> ids) async {
    for (final id in ids) {
      // Each request waits for the previous one
      await fetchUser(id);
    }
  }
}

āđƒāļŠāđ‰ Future.wait āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāđāļšāļšāļ‚āļ™āļēāļ™ āđāļĨāļ°āđƒāļŠāđ‰ async loop āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāļ•āļēāļĄāļĨāļģāļ”āļąāļš

FutureBuilder vs Riverpod

FutureBuilder āđ€āļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļšāļāļĢāļ“āļĩāļ—āļĩāđˆāđ„āļĄāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™ āđāļ•āđˆ Riverpod (AsyncValue) āđƒāļŦāđ‰āļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ–āđƒāļ™āļāļēāļĢāļˆāļąāļ”āļāļēāļĢ Cache, Error Handling āđāļĨāļ° Refresh āļ—āļĩāđˆāļ”āļĩāļāļ§āđˆāļēāļŠāļģāļŦāļĢāļąāļšāđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļ—āļĩāđˆāļĄāļĩāļ„āļ§āļēāļĄāļ‹āļąāļšāļ‹āđ‰āļ­āļ™āļŠāļđāļ‡

7. āļ­āļ˜āļīāļšāļēāļĒāđ€āļĢāļ·āđˆāļ­āļ‡ Stream āđāļĨāļ°āļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™

Stream āđāļ—āļ™āļĨāļģāļ”āļąāļšāļ„āđˆāļēāđāļšāļš Asynchronous āļ‹āļķāđˆāļ‡āđ€āļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļš Event āđāļšāļš Real-time āđ€āļŠāđˆāļ™ WebSocket, āļ‚āđ‰āļ­āļĄāļđāļĨāđ€āļ‹āđ‡āļ™āđ€āļ‹āļ­āļĢāđŒ āļŦāļĢāļ·āļ­āļāļēāļĢāđ‚āļ•āđ‰āļ•āļ­āļšāļ‚āļ­āļ‡āļœāļđāđ‰āđƒāļŠāđ‰

stream_example.dartdart
class MessageService {
  // StreamController manages creation and broadcasting
  final _messageController = StreamController<Message>.broadcast();

  // Expose only the Stream (not the Sink)
  Stream<Message> get messages => _messageController.stream;

  void addMessage(Message message) {
    _messageController.sink.add(message);
  }

  void dispose() {
    _messageController.close();
  }
}

// Usage with StreamBuilder
class MessageList extends StatelessWidget {
  final MessageService service;

  const MessageList({super.key, required this.service});

  
  Widget build(BuildContext context) {
    return StreamBuilder<Message>(
      stream: service.messages,
      builder: (context, snapshot) {
        // Handle all possible states
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator();
        }
        if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        }
        if (!snapshot.hasData) {
          return const Text('No messages');
        }
        return MessageCard(message: snapshot.data!);
      },
    );
  }
}

Stream āđāļšāļš .broadcast() āļ­āļ™āļļāļāļēāļ•āđƒāļŦāđ‰āļĄāļĩ Listener āļŦāļĨāļēāļĒāļ•āļąāļ§ āļ•āđˆāļēāļ‡āļˆāļēāļ Single-subscription Stream āļ—āļĩāđˆāļĢāļąāļš Listener āđ„āļ”āđ‰āđ€āļžāļĩāļĒāļ‡āļ•āļąāļ§āđ€āļ”āļĩāļĒāļ§

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Flutter āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄāđāļĨāļ° State Management

8. āđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļš State Management: Provider, Riverpod āđāļĨāļ° Bloc

āđāļ•āđˆāļĨāļ°āđ‚āļ‹āļĨāļđāļŠāļąāļ™āļ•āļ­āļšāđ‚āļˆāļ—āļĒāđŒāļ„āļ§āļēāļĄāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ—āļĩāđˆāđāļ•āļāļ•āđˆāļēāļ‡āļāļąāļ™ Provider āđ€āļ™āđ‰āļ™āļ„āļ§āļēāļĄāđ€āļĢāļĩāļĒāļšāļ‡āđˆāļēāļĒāđāļĨāļ°āļĢāļ­āļ‡āļĢāļąāļš Native Integration āļŠāđˆāļ§āļ™ Riverpod āļĄāļēāļžāļĢāđ‰āļ­āļĄ Type Safety āđāļĨāļ°āļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ–āđƒāļ™āļāļēāļĢāļ—āļ”āļŠāļ­āļš āļ‚āļ“āļ°āļ—āļĩāđˆ Bloc āļšāļąāļ‡āļ„āļąāļšāđƒāļŠāđ‰āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄāđāļšāļš Event-driven āļ­āļĒāđˆāļēāļ‡āđ€āļ‚āđ‰āļĄāļ‡āļ§āļ”

riverpod_example.dartdart
// Riverpod: declarative and type-safe approach
final userProvider = FutureProvider.autoDispose<User>((ref) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.fetchCurrentUser();
});

class UserProfile extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // AsyncValue handles loading/error/data
    final userAsync = ref.watch(userProvider);

    return userAsync.when(
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) => Text('Error: $error'),
      data: (user) => Text(user.displayName),
    );
  }
}
bloc_example.dartdart
// Bloc: explicit events/states separation
abstract class AuthEvent {}
class LoginRequested extends AuthEvent {
  final String email;
  final String password;
  LoginRequested(this.email, this.password);
}

abstract class AuthState {}
class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthSuccess extends AuthState {
  final User user;
  AuthSuccess(this.user);
}
class AuthFailure extends AuthState {
  final String error;
  AuthFailure(this.error);
}

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  AuthBloc() : super(AuthInitial()) {
    on<LoginRequested>(_onLoginRequested);
  }

  Future<void> _onLoginRequested(
    LoginRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading());
    try {
      final user = await _repository.login(event.email, event.password);
      emit(AuthSuccess(user));
    } catch (e) {
      emit(AuthFailure(e.toString()));
    }
  }
}

Riverpod āđ€āļ›āđ‡āļ™āļ•āļąāļ§āđ€āļĨāļ·āļ­āļāļ—āļĩāđˆāđāļ™āļ°āļ™āļģāļŠāļģāļŦāļĢāļąāļšāđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒāđƒāļŦāļĄāđˆ āđ€āļ™āļ·āđˆāļ­āļ‡āļˆāļēāļ API āļ—āļĩāđˆāļ—āļąāļ™āļŠāļĄāļąāļĒāđāļĨāļ°āļ„āļ§āļēāļĄāļ‡āđˆāļēāļĒāđƒāļ™āļāļēāļĢāļ—āļ”āļŠāļ­āļš

9. Clean Architecture āđƒāļ™ Flutter āļ„āļ·āļ­āļ­āļ°āđ„āļĢ?

Clean Architecture āđāļšāđˆāļ‡āđ‚āļ„āđ‰āļ”āļ­āļ­āļāđ€āļ›āđ‡āļ™ Layer āļ—āļĩāđˆāđ€āļ›āđ‡āļ™āļ­āļīāļŠāļĢāļ°āļˆāļēāļāļāļąāļ™ āđ„āļ”āđ‰āđāļāđˆ Domain (Business Logic), Data (āđāļŦāļĨāđˆāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨ) āđāļĨāļ° Presentation (UI) āļāļēāļĢāđāļšāđˆāļ‡āđāļĒāļāļ™āļĩāđ‰āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļāļēāļĢāļ—āļ”āļŠāļ­āļšāđāļĨāļ°āļāļēāļĢāļ”āļđāđāļĨāļĢāļąāļāļĐāļēāļ—āļģāđ„āļ”āđ‰āļ‡āđˆāļēāļĒāļ‚āļķāđ‰āļ™

domain/entities/user.dartdart
// Entity: pure business object, no framework dependency
class User {
  final String id;
  final String email;
  final String name;

  const User({
    required this.id,
    required this.email,
    required this.name,
  });
}

// domain/repositories/user_repository.dart
// Interface: abstract contract, implementation in Data
abstract class UserRepository {
  Future<User> getUser(String id);
  Future<void> updateUser(User user);
}

// domain/usecases/get_user_usecase.dart
// Use case: isolated business logic
class GetUserUseCase {
  final UserRepository _repository;

  GetUserUseCase(this._repository);

  Future<User> call(String userId) {
    return _repository.getUser(userId);
  }
}
data/repositories/user_repository_impl.dartdart
// Concrete implementation with data sources
class UserRepositoryImpl implements UserRepository {
  final UserRemoteDataSource _remoteDataSource;
  final UserLocalDataSource _localDataSource;

  UserRepositoryImpl(this._remoteDataSource, this._localDataSource);

  
  Future<User> getUser(String id) async {
    try {
      // Try local cache first
      final cachedUser = await _localDataSource.getUser(id);
      if (cachedUser != null) return cachedUser;
    } catch (_) {}

    // Fallback to API
    final user = await _remoteDataSource.fetchUser(id);
    await _localDataSource.cacheUser(user);
    return user;
  }
}

Domain Layer āđ„āļĄāđˆāļžāļķāđˆāļ‡āļžāļē Layer āļ­āļ·āđˆāļ™, Data Layer āļžāļķāđˆāļ‡āļžāļē Domain āđāļĨāļ° Presentation Layer āļžāļķāđˆāļ‡āļžāļēāļ—āļąāđ‰āļ‡āļŠāļ­āļ‡

10. āļāļēāļĢāļ—āļģ Dependency Injection āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Dependency Injection āđāļĒāļ Component āļ­āļ­āļāļˆāļēāļāļāļąāļ™āđ‚āļ”āļĒāļāļēāļĢāļŠāđˆāļ‡ Dependency āļˆāļēāļāļ āļēāļĒāļ™āļ­āļ Riverpod āļ—āļģāđ€āļĢāļ·āđˆāļ­āļ‡āļ™āļĩāđ‰āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĒāļ­āļ”āđ€āļĒāļĩāđˆāļĒāļĄāļœāđˆāļēāļ™āļĢāļ°āļšāļš Provider

di_example.dartdart
// Provider definitions (dependencies)
final apiClientProvider = Provider<ApiClient>((ref) {
  return ApiClient(baseUrl: Environment.apiUrl);
});

final userRepositoryProvider = Provider<UserRepository>((ref) {
  // Automatically injects ApiClient
  final client = ref.watch(apiClientProvider);
  return UserRepositoryImpl(client);
});

final getUserUseCaseProvider = Provider<GetUserUseCase>((ref) {
  final repository = ref.watch(userRepositoryProvider);
  return GetUserUseCase(repository);
});

// Usage in a widget
class UserScreen extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final getUserUseCase = ref.watch(getUserUseCaseProvider);
    // Use the use case...
  }
}

// Tests: easy dependency override
void main() {
  testWidgets('displays user', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [
          // Replace with mock for tests
          userRepositoryProvider.overrideWithValue(MockUserRepository()),
        ],
        child: const MyApp(),
      ),
    );
  });
}

āļ‚āđ‰āļ­āđ„āļ”āđ‰āđ€āļ›āļĢāļĩāļĒāļšāļŦāļĨāļąāļāļ„āļ·āļ­ āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļŠāļēāļĄāļēāļĢāļ–āđāļ—āļ™āļ—āļĩāđˆ Dependency āđƒāļ” āđ† āļ”āđ‰āļ§āļĒ Mock āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļ‡āđˆāļēāļĒāļ”āļēāļĒ

āļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž

11. āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļāļēāļĢ Rebuild āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

āļāļēāļĢāļĨāļ”āļˆāļģāļ™āļ§āļ™ Rebuild āļ—āļĩāđˆāđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļŠāđˆāļ§āļĒāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ‚āļ­āļ‡āđāļ­āļ›āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĄāļēāļ āđ€āļ—āļ„āļ™āļīāļ„āļŦāļĨāļąāļāļ›āļĢāļ°āļāļ­āļšāļ”āđ‰āļ§āļĒ const Widget, āļāļēāļĢāđāļšāđˆāļ‡ Widget āđƒāļŦāđ‰āđ€āļĨāđ‡āļāļĨāļ‡ āđāļĨāļ° Riverpod Selector

rebuild_optimization.dartdart
// ❌ Bad: everything rebuilds on each change
class BadExample extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userProvider);
    return Column(
      children: [
        Text(user.name),
        Text(user.email),
        const ExpensiveWidget(), // Rebuilds unnecessarily
      ],
    );
  }
}

// ✅ Good: selector to rebuild only if name changes
class GoodExample extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // select: rebuilds only if name changes
    final name = ref.watch(userProvider.select((u) => u.name));
    return Text(name);
  }
}

// ✅ Good: splitting into smaller widgets
class OptimizedScreen extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        const Header(), // Static, never rebuilds
        const UserNameWidget(), // Rebuilds if name changes
        const UserEmailWidget(), // Rebuilds if email changes
        const Footer(), // Static
      ],
    );
  }
}

āđƒāļŠāđ‰ DevTools Performance āđ€āļžāļ·āđˆāļ­āļ•āļĢāļ§āļˆāļˆāļąāļš Rebuild āļ—āļĩāđˆāļĄāļēāļāđ€āļāļīāļ™āđ„āļ›

12. āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļĢāļēāļĒāļāļēāļĢāļĒāļēāļ§ āđ† āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

āļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĄāļĩāļˆāļģāļ™āļ§āļ™āļĄāļēāļāļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰ Lazy Loading āļ”āđ‰āļ§āļĒ ListView.builder āļ„āļ§āļĢāļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāđƒāļŠāđ‰ ListView āļ—āļĩāđˆāļĄāļĩ Children āđ‚āļ”āļĒāļ•āļĢāļ‡āđ€āļĄāļ·āđˆāļ­āļĄāļĩāļĢāļēāļĒāļāļēāļĢāļĄāļēāļāļāļ§āđˆāļē 20 āļĢāļēāļĒāļāļēāļĢ

list_optimization.dartdart
class OptimizedList extends StatelessWidget {
  final List<Item> items;

  const OptimizedList({super.key, required this.items});

  
  Widget build(BuildContext context) {
    // ✅ ListView.builder: builds on demand
    return ListView.builder(
      // Fixed height improves scrolling
      itemExtent: 72,
      itemCount: items.length,
      itemBuilder: (context, index) {
        return ItemTile(
          // Key to preserve state during scroll
          key: ValueKey(items[index].id),
          item: items[index],
        );
      },
    );
  }
}

// List widget with infinite loading
class InfiniteList extends ConsumerStatefulWidget {
  
  ConsumerState<InfiniteList> createState() => _InfiniteListState();
}

class _InfiniteListState extends ConsumerState<InfiniteList> {
  final _scrollController = ScrollController();

  
  void initState() {
    super.initState();
    _scrollController.addListener(_onScroll);
  }

  void _onScroll() {
    // Load more data near the end
    if (_scrollController.position.pixels >=
        _scrollController.position.maxScrollExtent - 200) {
      ref.read(itemsProvider.notifier).loadMore();
    }
  }

  
  Widget build(BuildContext context) {
    final items = ref.watch(itemsProvider);
    return ListView.builder(
      controller: _scrollController,
      itemCount: items.length,
      itemBuilder: (context, index) => ItemTile(item: items[index]),
    );
  }
}

āļŠāļģāļŦāļĢāļąāļšāļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĒāļēāļ§āļĄāļēāļ (1,000 āļĢāļēāļĒāļāļēāļĢāļ‚āļķāđ‰āļ™āđ„āļ›) āļ„āļ§āļĢāļžāļīāļˆāļēāļĢāļ“āļēāđƒāļŠāđ‰ ListView.separated āļŦāļĢāļ·āļ­ Package āđ€āļ‰āļžāļēāļ°āļ—āļēāļ‡ āđ€āļŠāđˆāļ™ scrollable_positioned_list

āđāļ„āļŠāļĢāļđāļ›āļ āļēāļž

āļŠāļģāļŦāļĢāļąāļšāļĢāļēāļĒāļāļēāļĢāļ—āļĩāđˆāļĄāļĩāļĢāļđāļ›āļ āļēāļž āļ„āļ§āļĢāđƒāļŠāđ‰ cached_network_image āđ€āļžāļ·āđˆāļ­āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāđ‚āļŦāļĨāļ”āļ‹āđ‰āļģ āļĢāļđāļ›āļ āļēāļžāļ—āļĩāđˆāđ„āļĄāđˆāđ„āļ”āđ‰āđāļ„āļŠāļˆāļ°āļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ”āļ­āļēāļāļēāļĢāļāļĢāļ°āļ•āļļāļāļ‚āļ“āļ°āđ€āļĨāļ·āđˆāļ­āļ™āļŦāļ™āđ‰āļēāļˆāļ­

13. āļ­āļ˜āļīāļšāļēāļĒāļāļēāļĢāļ—āļģāļ‡āļēāļ™āļ‚āļ­āļ‡ Impeller Rendering Engine

Impeller āđ€āļ‚āđ‰āļēāļĄāļēāđāļ—āļ™āļ—āļĩāđˆ Skia āđƒāļ™āļāļēāļ™āļ° Rendering Engine āđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ (Flutter 3.16+) āđ‚āļ”āļĒāļ—āļģāļāļēāļĢ Precompile Shader āđ€āļžāļ·āđˆāļ­āļāļģāļˆāļąāļ”āļ­āļēāļāļēāļĢ "Jank" āđƒāļ™āļāļēāļĢāđāļŠāļ”āļ‡āļœāļĨāļ„āļĢāļąāđ‰āļ‡āđāļĢāļ

impeller_benefits.dartdart
// Complex animations benefit from Impeller
class SmoothAnimation extends StatefulWidget {
  
  State<SmoothAnimation> createState() => _SmoothAnimationState();
}

class _SmoothAnimationState extends State<SmoothAnimation>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat();
  }

  
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        // Impeller: no runtime shader compilation
        return Transform.rotate(
          angle: _controller.value * 2 * 3.14159,
          child: child,
        );
      },
      child: const FlutterLogo(size: 100),
    );
  }
}

Impeller āļ–āļđāļāđ€āļ›āļīāļ”āđƒāļŠāđ‰āļ‡āļēāļ™āđ‚āļ”āļĒāļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āļšāļ™ iOS āļŠāļģāļŦāļĢāļąāļš Android āļŠāļēāļĄāļēāļĢāļ–āļ•āļĢāļ§āļˆāļŠāļ­āļšāļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāļāļąāļ™āđ„āļ”āđ‰āļ”āđ‰āļ§āļĒāļ„āļģāļŠāļąāđˆāļ‡ flutter run --enable-impeller

āļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāļāļēāļĢāļ™āļģāļ—āļēāļ‡āđāļĨāļ°āļŸāļ­āļĢāđŒāļĄ

14. āļāļēāļĢāļˆāļąāļ”āļāļēāļĢ Navigation āļ”āđ‰āļ§āļĒ Deep Linking āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Deep Linking āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļŠāļēāļĄāļēāļĢāļ–āđ€āļ›āļīāļ”āđāļ­āļ›āđ„āļ›āļĒāļąāļ‡āļŦāļ™āđ‰āļēāļˆāļ­āļ—āļĩāđˆāļāļģāļŦāļ™āļ”āļœāđˆāļēāļ™ URL āđ„āļ”āđ‰āđ‚āļ”āļĒāļ•āļĢāļ‡ GoRouter āļĢāļ­āļ‡āļĢāļąāļšāļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ™āļĩāđ‰āđāļšāļš Native

deep_linking.dartdart
final router = GoRouter(
  routes: [
    GoRoute(
      path: '/products/:productId',
      builder: (context, state) {
        // Extract URL parameter
        final productId = state.pathParameters['productId']!;
        return ProductScreen(productId: productId);
      },
    ),
    GoRoute(
      path: '/search',
      builder: (context, state) {
        // Query parameters (?query=flutter)
        final query = state.uri.queryParameters['query'] ?? '';
        return SearchScreen(initialQuery: query);
      },
    ),
  ],
);

// Programmatic navigation
void navigateToProduct(BuildContext context, String id) {
  // go: replaces navigation stack
  context.go('/products/$id');

  // push: adds to stack (allows back)
  context.push('/products/$id');

  // pushNamed with extra for complex data
  context.pushNamed(
    'productDetail',
    pathParameters: {'productId': id},
    extra: ProductData(id: id),
  );
}

āļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āļ•āļąāđ‰āļ‡āļ„āđˆāļēāđ„āļŸāļĨāđŒ Native (AndroidManifest.xml, Info.plist) āđ€āļžāļ·āđˆāļ­āđ€āļ›āļīāļ”āđƒāļŠāđ‰āļ‡āļēāļ™ Deep Linking āđƒāļ™āļĢāļ°āļ”āļąāļšāļĢāļ°āļšāļšāļ›āļāļīāļšāļąāļ•āļīāļāļēāļĢ

15. āļāļēāļĢ Validate āļŸāļ­āļĢāđŒāļĄāļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

āļāļēāļĢ Validate āļĢāļ§āļĄ Form, TextFormField āđāļĨāļ° Custom Validator āđ€āļ‚āđ‰āļēāļ”āđ‰āļ§āļĒāļāļąāļ™ Package āļ­āļĒāđˆāļēāļ‡ formz āļŠāđˆāļ§āļĒāđ€āļžāļīāđˆāļĄāđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āļ—āļĩāđˆāļŠāļąāļ”āđ€āļˆāļ™āļ„āļĨāđ‰āļēāļĒāļāļąāļš Zod

form_validation.dartdart
class RegistrationForm extends StatefulWidget {
  
  State<RegistrationForm> createState() => _RegistrationFormState();
}

class _RegistrationFormState extends State<RegistrationForm> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmController = TextEditingController();

  
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      // Real-time validation
      autovalidateMode: AutovalidateMode.onUserInteraction,
      child: Column(
        children: [
          TextFormField(
            controller: _emailController,
            decoration: const InputDecoration(labelText: 'Email'),
            keyboardType: TextInputType.emailAddress,
            validator: _validateEmail,
          ),
          TextFormField(
            controller: _passwordController,
            decoration: const InputDecoration(labelText: 'Password'),
            obscureText: true,
            validator: _validatePassword,
          ),
          TextFormField(
            controller: _confirmController,
            decoration: const InputDecoration(labelText: 'Confirm'),
            obscureText: true,
            validator: _validateConfirmPassword,
          ),
          ElevatedButton(
            onPressed: _submit,
            child: const Text('Create account'),
          ),
        ],
      ),
    );
  }

  String? _validateEmail(String? value) {
    if (value == null || value.isEmpty) {
      return 'Email required';
    }
    final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
    if (!emailRegex.hasMatch(value)) {
      return 'Invalid email format';
    }
    return null;
  }

  String? _validatePassword(String? value) {
    if (value == null || value.length < 8) {
      return 'Minimum 8 characters';
    }
    if (!value.contains(RegExp(r'[A-Z]'))) {
      return 'At least one uppercase letter required';
    }
    if (!value.contains(RegExp(r'[0-9]'))) {
      return 'At least one number required';
    }
    return null;
  }

  String? _validateConfirmPassword(String? value) {
    if (value != _passwordController.text) {
      return 'Passwords do not match';
    }
    return null;
  }

  void _submit() {
    if (_formKey.currentState!.validate()) {
      // Form is valid, proceed
    }
  }
}

āđ‚āļŦāļĄāļ” AutovalidateMode.onUserInteraction āđƒāļŦāđ‰ UX āļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ” āđ€āļžāļĢāļēāļ°āđāļŠāļ”āļ‡ Error āļŦāļĨāļąāļ‡āļˆāļēāļāļœāļđāđ‰āđƒāļŠāđ‰āđ‚āļ•āđ‰āļ•āļ­āļšāļāļąāļšāļŸāļīāļĨāļ”āđŒāđāļĨāđ‰āļ§āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™

āļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāļāļēāļĢāļ—āļ”āļŠāļ­āļš

16. āļāļēāļĢāļ—āļ”āļŠāļ­āļš Widget āđƒāļ™ Flutter āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Widget Test āļŠāđˆāļ§āļĒāļ•āļĢāļ§āļˆāļŠāļ­āļš UI āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļžāļķāđˆāļ‡āļžāļēāļ­āļļāļ›āļāļĢāļ“āđŒāļˆāļĢāļīāļ‡ Package flutter_test āļĄāļĩāđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļ—āļąāđ‰āļ‡āļŦāļĄāļ”

widget_test.dartdart
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  testWidgets('displays welcome message', (tester) async {
    // Arrange: build the widget
    await tester.pumpWidget(
      const ProviderScope(
        child: MaterialApp(
          home: WelcomeScreen(username: 'Alice'),
        ),
      ),
    );

    // Assert: verify content
    expect(find.text('Welcome, Alice'), findsOneWidget);
  });

  testWidgets('button increments counter', (tester) async {
    await tester.pumpWidget(
      const MaterialApp(home: CounterScreen()),
    );

    // Initial state
    expect(find.text('0'), findsOneWidget);

    // Act: tap the button
    await tester.tap(find.byType(ElevatedButton));
    await tester.pump(); // Rebuild after setState

    // Assert: counter incremented
    expect(find.text('1'), findsOneWidget);
  });

  testWidgets('form validates email', (tester) async {
    await tester.pumpWidget(
      const MaterialApp(home: LoginForm()),
    );

    // Enter invalid email
    await tester.enterText(
      find.byKey(const Key('email-field')),
      'invalid-email',
    );
    await tester.tap(find.byType(ElevatedButton));
    await tester.pump();

    // Verify error message
    expect(find.text('Invalid email format'), findsOneWidget);
  });
}

pump() āđ€āļĨāļ·āđˆāļ­āļ™āđ„āļ›āļŦāļ™āļķāđˆāļ‡āđ€āļŸāļĢāļĄ āļŠāđˆāļ§āļ™ pumpAndSettle() āļĢāļ­āļˆāļ™āļāļ§āđˆāļē Animation āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļˆāļ°āđ€āļŠāļĢāđ‡āļˆāļŠāļĄāļšāļđāļĢāļ“āđŒ

17. āļāļēāļĢāļ—āļ”āļŠāļ­āļš Riverpod Provider āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Riverpod āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ—āļģāđ„āļ”āđ‰āļ‡āđˆāļēāļĒāļœāđˆāļēāļ™ ProviderContainer āđāļĨāļ°āļĢāļ°āļšāļš Override

provider_test.dartdart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

// Repository mock
class MockUserRepository extends Mock implements UserRepository {}

void main() {
  late MockUserRepository mockRepository;
  late ProviderContainer container;

  setUp(() {
    mockRepository = MockUserRepository();
    container = ProviderContainer(
      overrides: [
        userRepositoryProvider.overrideWithValue(mockRepository),
      ],
    );
  });

  tearDown(() {
    container.dispose();
  });

  test('loads user from repository', () async {
    // Arrange
    final expectedUser = User(id: '1', name: 'Test');
    when(() => mockRepository.getUser('1'))
        .thenAnswer((_) async => expectedUser);

    // Act
    final user = await container.read(userProvider('1').future);

    // Assert
    expect(user, expectedUser);
    verify(() => mockRepository.getUser('1')).called(1);
  });

  test('handles repository error', () async {
    when(() => mockRepository.getUser(any()))
        .thenThrow(Exception('Network error'));

    expect(
      () => container.read(userProvider('1').future),
      throwsException,
    );
  });
}

āļāļēāļĢāļ—āļ”āļŠāļ­āļš Provider āļ—āļģāļ‡āļēāļ™āđ„āļ”āđ‰āļĢāļ§āļ”āđ€āļĢāđ‡āļ§āđ€āļžāļĢāļēāļ°āđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡ Render UI

āļ„āļģāļ–āļēāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāļāļēāļĢ Deploy

18. āļāļēāļĢāļˆāļąāļ”āļāļēāļĢ Environment (dev, staging, prod) āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Environment āļāļģāļŦāļ™āļ”āļ„āđˆāļēāļœāđˆāļēāļ™āđ„āļŸāļĨāđŒ .env āļŦāļĢāļ·āļ­ Compile-time Constant āļ”āđ‰āļ§āļĒ --dart-define

environment.dartdart
enum Environment { dev, staging, prod }

class AppConfig {
  final Environment environment;
  final String apiUrl;
  final bool enableAnalytics;

  const AppConfig._({
    required this.environment,
    required this.apiUrl,
    required this.enableAnalytics,
  });

  // Predefined configurations
  static const dev = AppConfig._(
    environment: Environment.dev,
    apiUrl: 'https://api-dev.example.com',
    enableAnalytics: false,
  );

  static const staging = AppConfig._(
    environment: Environment.staging,
    apiUrl: 'https://api-staging.example.com',
    enableAnalytics: true,
  );

  static const prod = AppConfig._(
    environment: Environment.prod,
    apiUrl: 'https://api.example.com',
    enableAnalytics: true,
  );

  // Read from --dart-define
  static AppConfig fromEnvironment() {
    const env = String.fromEnvironment('ENV', defaultValue: 'dev');
    switch (env) {
      case 'prod':
        return prod;
      case 'staging':
        return staging;
      default:
        return dev;
    }
  }
}
bash
# terminal
# Launch with specific environment
flutter run --dart-define=ENV=staging

# Production build
flutter build apk --dart-define=ENV=prod --release

19. āļāļēāļĢāļ—āļģ Flavoring āļŠāļģāļŦāļĢāļąāļšāđāļ­āļ›āļŦāļĨāļēāļĒāđ€āļ§āļ­āļĢāđŒāļŠāļąāļ™āļ—āļģāļ­āļĒāđˆāļēāļ‡āđ„āļĢ?

Flavoring āļŠāļĢāđ‰āļēāļ‡āđāļ­āļ›āļŦāļĨāļēāļĒāđ€āļ§āļ­āļĢāđŒāļŠāļąāļ™ (client1, client2) āļ—āļĩāđˆāļĄāļĩāļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļēāđāļ•āļāļ•āđˆāļēāļ‡āļāļąāļ™ (āđ„āļ­āļ„āļ­āļ™, āļŠāļ·āđˆāļ­, API)

main_client1.dartdart
import 'package:flutter/material.dart';
import 'config/flavor_config.dart';
import 'app.dart';

void main() {
  FlavorConfig(
    flavor: Flavor.client1,
    name: 'App Client 1',
    apiUrl: 'https://api.client1.com',
    primaryColor: Colors.blue,
  );
  runApp(const App());
}

// config/flavor_config.dart
enum Flavor { client1, client2, internal }

class FlavorConfig {
  final Flavor flavor;
  final String name;
  final String apiUrl;
  final Color primaryColor;

  // Singleton for global access
  static FlavorConfig? _instance;
  static FlavorConfig get instance => _instance!;

  FlavorConfig({
    required this.flavor,
    required this.name,
    required this.apiUrl,
    required this.primaryColor,
  }) {
    _instance = this;
  }

  bool get isProduction => flavor != Flavor.internal;
}

āļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āļ•āļąāđ‰āļ‡āļ„āđˆāļēāđ„āļŸāļĨāđŒ Native āļ—āļąāđ‰āļ‡ Android (build.gradle) āđāļĨāļ° iOS (xcconfig) āļŠāļģāļŦāļĢāļąāļšāđāļ•āđˆāļĨāļ° Flavor

20. āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ”āđ‰āļēāļ™āļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒāļ‚āļ­āļ‡ Flutter āļĄāļĩāļ­āļ°āđ„āļĢāļšāđ‰āļēāļ‡?

āļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒāļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļāļēāļĢāļˆāļąāļ”āđ€āļāđ‡āļšāļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļĨāļ°āđ€āļ­āļĩāļĒāļ”āļ­āđˆāļ­āļ™, āļāļēāļĢ Validate Input āđāļĨāļ°āļāļēāļĢāļ›āđ‰āļ­āļ‡āļāļąāļ™ Reverse Engineering

security_example.dartdart
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class SecureStorage {
  // Encrypted storage for sensitive data
  final _storage = const FlutterSecureStorage(
    aOptions: AndroidOptions(encryptedSharedPreferences: true),
    iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
  );

  Future<void> saveToken(String token) async {
    await _storage.write(key: 'auth_token', value: token);
  }

  Future<String?> getToken() async {
    return _storage.read(key: 'auth_token');
  }

  Future<void> deleteToken() async {
    await _storage.delete(key: 'auth_token');
  }
}

// Input validation
class InputValidator {
  // Injection prevention
  static String sanitize(String input) {
    return input
        .replaceAll(RegExp(r'[<>"\']'), '')
        .trim();
  }

  // Length validation
  static bool isValidLength(String input, int min, int max) {
    return input.length >= min && input.length <= max;
  }
}

// SSL pinning protection
class SecureApiClient {
  Dio createSecureClient() {
    final dio = Dio();
    // Add certificate pinning
    (dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
      final client = HttpClient();
      client.badCertificateCallback = (cert, host, port) {
        // Verify certificate fingerprint
        return _isValidCertificate(cert);
      };
      return client;
    };
    return dio;
  }
}

āđ„āļĄāđˆāļ„āļ§āļĢāđ€āļāđ‡āļš Secret āđ„āļ§āđ‰āđƒāļ™āđ‚āļ„āđ‰āļ”āđ‚āļ”āļĒāđ€āļ”āđ‡āļ”āļ‚āļēāļ” āđƒāļŠāđ‰ flutter_secure_storage āļŠāļģāļŦāļĢāļąāļš Token āđāļĨāļ°āđƒāļŠāđ‰ --obfuscate āļŠāļģāļŦāļĢāļąāļš Production Build

āļŠāļĢāļļāļ›

āļ„āļģāļ–āļēāļĄ 20 āļ‚āđ‰āļ­āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļ—āļļāļāđāļ‡āđˆāļĄāļļāļĄāļ—āļĩāđˆāļŠāļģāļ„āļąāļāļ‚āļ­āļ‡āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™ Flutter āļ•āļąāđ‰āļ‡āđāļ•āđˆāļžāļ·āđ‰āļ™āļāļēāļ™āļ‚āļ­āļ‡ Framework, āļ„āļ§āļēāļĄāđ€āļŠāļĩāđˆāļĒāļ§āļŠāļēāļāļ”āđ‰āļēāļ™ Dart, āļĢāļđāļ›āđāļšāļšāļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄ āđ„āļ›āļˆāļ™āļ–āļķāļ‡āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļŠāļģāļŦāļĢāļąāļš Production āļ„āļ§āļēāļĄāļŠāļģāđ€āļĢāđ‡āļˆāđƒāļ™āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ­āļĒāļđāđˆāļ—āļĩāđˆāļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāđƒāļˆāđ€āļŠāļīāļ‡āļĨāļķāļāļ‚āļ­āļ‡āļāļĨāđ„āļāđ€āļšāļ·āđ‰āļ­āļ‡āļŦāļĨāļąāļ‡ āđ„āļĄāđˆāđƒāļŠāđˆāđāļ„āđˆāđ„āļ§āļĒāļēāļāļĢāļ“āđŒ

āļĢāļēāļĒāļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļāđˆāļ­āļ™āļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

  • ✅ āđ€āļ‚āđ‰āļēāđƒāļˆāļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āļĢāļ°āļŦāļ§āđˆāļēāļ‡ StatelessWidget āļāļąāļš StatefulWidget āđāļĨāļ°āļāļĢāļ“āļĩāļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™
  • ✅ āđ€āļ‚āđ‰āļēāđƒāļˆ Widget Tree āđāļĨāļ°āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļāļēāļĢ Rebuild
  • ✅ āļāļķāļāļāļ™ async/await, Future āđāļĨāļ° Stream āļ”āđ‰āļ§āļĒāđāļšāļšāļāļķāļāļŦāļąāļ”āļˆāļĢāļīāļ‡
  • ✅ āļŠāļĢāđ‰āļēāļ‡āđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒāļ”āđ‰āļ§āļĒ Riverpod āļŠāļģāļŦāļĢāļąāļš State Management
  • ✅ āļĢāļđāđ‰āļˆāļąāļ GoRouter āđāļĨāļ° Deep Linking
  • ✅ āđ€āļ‚āļĩāļĒāļ™ Unit Test āđāļĨāļ° Widget Test
  • ✅ āđ€āļ‚āđ‰āļēāđƒāļˆāļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļē Multi-environment

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļāļēāļĢāļāļķāļāļāļ™āļ­āļĒāđˆāļēāļ‡āļŠāļĄāđˆāļģāđ€āļŠāļĄāļ­āđƒāļ™āđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒāļŠāđˆāļ§āļ™āļ•āļąāļ§āļĒāļąāļ‡āļ„āļ‡āđ€āļ›āđ‡āļ™āļ§āļīāļ˜āļĩāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āđƒāļ™āļāļēāļĢāđ€āļŠāļĢāļīāļĄāļŠāļĢāđ‰āļēāļ‡āļ„āļ§āļēāļĄāļĢāļđāđ‰āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰ āđāļ•āđˆāļĨāļ°āļ„āļģāļ–āļēāļĄāļ—āļĩāđˆāļāļĨāđˆāļēāļ§āļĄāļēāļ„āļ§āļĢāđ„āļ”āđ‰āļĢāļąāļšāļāļēāļĢāļĻāļķāļāļĐāļēāđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄāđƒāļ™āđ€āļŠāļīāļ‡āļĨāļķāļāļ”āđ‰āļ§āļĒāđ‚āļ„āđ‰āļ”āļˆāļĢāļīāļ‡āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āđ€āļ‚āđ‰āļēāđƒāļˆāļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”āļ›āļĨāļĩāļāļĒāđˆāļ­āļĒāļ‚āļ­āļ‡ Flutter Framework āļ­āļĒāđˆāļēāļ‡āļ–āđˆāļ­āļ‡āđāļ—āđ‰

āđāļ—āđ‡āļ

#flutter
#dart
#interview
#mobile development
#technical interview

āđāļŠāļĢāđŒ

āļšāļ—āļ„āļ§āļēāļĄāļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡

āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļĄāļ·āļ­āļ–āļ·āļ­āļ•āļąāļ§āđāļĢāļāļ”āđ‰āļ§āļĒ Flutter āđāļĨāļ° Dart

Flutter: āļŠāļĢāđ‰āļēāļ‡āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļ‚āđ‰āļēāļĄāđāļžāļĨāļ•āļŸāļ­āļĢāđŒāļĄāļ•āļąāļ§āđāļĢāļ

āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļĄāļ·āļ­āļ–āļ·āļ­āļ‚āđ‰āļēāļĄāđāļžāļĨāļ•āļŸāļ­āļĢāđŒāļĄāļ”āđ‰āļ§āļĒ Flutter āđāļĨāļ° Dart āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄ Widget āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļŠāļ–āļēāļ™āļ° āļāļēāļĢāļ™āļģāļ—āļēāļ‡ āđāļĨāļ°āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļŠāļģāļŦāļĢāļąāļšāļœāļđāđ‰āđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™

āļāļēāļĢāļœāļŠāļēāļ™āļĢāļ§āļĄ Flutter āđāļĨāļ° Firebase āđāļŠāļ”āļ‡āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄāļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™āđāļĨāļ°āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ Firestore

Flutter āđāļĨāļ° Firebase āđƒāļ™āļ›āļĩ 2026: āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™, Firestore āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

āđ€āļˆāļēāļ°āļĨāļķāļ Flutter Firebase: āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™āļ”āđ‰āļ§āļĒ firebase_auth, CRUD āļ‚āļ­āļ‡ Firestore āđāļĨāļ°āļŠāļ•āļĢāļĩāļĄāđāļšāļšāđ€āļĢāļĩāļĒāļĨāđ„āļ—āļĄāđŒ, āļāļŽāļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒ āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”

āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļ—āļ”āļŠāļ­āļš Flutter āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄ widget test, integration test āđāļĨāļ°āđāļ™āļ§āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļŠāļēāļĒāđ€āļ—āļ„āļ™āļīāļ„

āļāļēāļĢāļ—āļ”āļŠāļ­āļš Flutter āļ­āļĒāđˆāļēāļ‡āļ„āļĢāļšāļ–āđ‰āļ§āļ™: Widget Test, Integration Test āđāļĨāļ°āļāļĨāļĒāļļāļ—āļ˜āđŒāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļŠāļēāļĒāđ€āļ—āļ„āļ™āļīāļ„ 2026

āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļ—āļ”āļŠāļ­āļš Flutter āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ: widget test, integration test, golden test āđāļĨāļ° mocking āļ”āđ‰āļ§āļĒ Mocktail āļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āļˆāļĢāļīāļ‡āđāļĨāļ°āđāļ™āļ§āļ—āļēāļ‡āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāđƒāļ™āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļŠāļēāļĒāđ€āļ—āļ„āļ™āļīāļ„ 2026