Dart & Flutter Expert
Expert guidance for Dart programming, Flutter framework, mobile development, and cross-platform applications.
Core Concepts Dart Language Strong typing with type inference Async/await and Futures Streams Mixins and extensions Null safety Collections Flutter Framework Widgets (Stateless & Stateful) State management (Provider, Riverpod, Bloc) Navigation and routing Material and Cupertino design Responsive layouts Platform integration Dart Fundamentals // Variables and types var name = 'John'; // Type inference String explicitType = 'Explicit'; final constantValue = 42; // Runtime constant const compileConstant = 'Compile-time';
// Null safety String? nullableString; String nonNullable = 'Never null';
// Late initialization late String lateInit;
// Collections
List
// Functions int add(int a, int b) => a + b;
// Named parameters void createUser({ required String name, int age = 18, String? email, }) { print('Creating user: $name, age: $age'); }
// Classes class User { final String id; final String name; int age;
User({ required this.id, required this.name, this.age = 0, });
// Named constructor User.guest() : this(id: 'guest', name: 'Guest');
// Methods void celebrateBirthday() { age++; }
@override String toString() => 'User($name, $age)'; }
// Mixins mixin Loggable { void log(String message) { print('[${DateTime.now()}] $message'); } }
class LoggableUser extends User with Loggable { LoggableUser({required String id, required String name}) : super(id: id, name: name); }
// Extensions extension StringExtensions on String { bool get isValidEmail => contains('@') && contains('.'); String capitalize() => '${this[0].toUpperCase()}${substring(1)}'; }
Async Programming import 'dart:async';
// Future
Future
// Error handling
Future
// Multiple futures
Future
// Streams
Stream
// Listen to stream void listenToStream() { countStream().listen( (data) => print('Received: $data'), onError: (error) => print('Error: $error'), onDone: () => print('Done'), ); }
// Stream transformations
Stream
// StreamController
class Counter {
final _controller = StreamController
Stream
void increment(int value) { _controller.add(value); }
void dispose() { _controller.close(); } }
Flutter Widgets import 'package:flutter/material.dart';
// Stateless Widget class UserCard extends StatelessWidget { final User user;
const UserCard({Key? key, required this.user}) : super(key: key);
@override Widget build(BuildContext context) { return Card( child: ListTile( title: Text(user.name), subtitle: Text('Age: ${user.age}'), trailing: Icon(Icons.arrow_forward), ), ); } }
// Stateful Widget class CounterWidget extends StatefulWidget { const CounterWidget({Key? key}) : super(key: key);
@override
State
class _CounterWidgetState extends State
void _incrementCounter() { setState(() { _counter++; }); }
@override Widget build(BuildContext context) { return Column( children: [ Text('Counter: $_counter'), ElevatedButton( onPressed: _incrementCounter, child: Text('Increment'), ), ], ); } }
// Layout
class UserListScreen extends StatelessWidget {
final List
const UserListScreen({Key? key, required this.users}) : super(key: key);
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Users'), actions: [ IconButton( icon: Icon(Icons.add), onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (_) => AddUserScreen()), ), ), ], ), body: ListView.builder( itemCount: users.length, itemBuilder: (context, index) { return UserCard(user: users[index]); }, ), ); } }
State Management (Provider) import 'package:provider/provider.dart';
// State class
class UserProvider extends ChangeNotifier {
List
List
Future
void addUser(User user) { _users.add(user); notifyListeners(); }
void removeUser(String id) { _users.removeWhere((user) => user.id == id); notifyListeners(); } }
// Setup provider void main() { runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: () => UserProvider()), ChangeNotifierProvider(create: () => AuthProvider()), ], child: MyApp(), ), ); }
// Consume provider
class UserList extends StatelessWidget {
@override
Widget build(BuildContext context) {
final userProvider = Provider.of
return ListView.builder(
itemCount: userProvider.users.length,
itemBuilder: (context, index) {
final user = userProvider.users[index];
return ListTile(
title: Text(user.name),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => userProvider.removeUser(user.id),
),
);
},
);
} }
// Consumer widget
class UserCounter extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer
Navigation // Basic navigation Navigator.push( context, MaterialPageRoute(builder: (context) => DetailScreen()), );
// Named routes MaterialApp( routes: { '/': (context) => HomeScreen(), '/details': (context) => DetailScreen(), '/settings': (context) => SettingsScreen(), }, );
Navigator.pushNamed(context, '/details');
// Pass arguments Navigator.pushNamed( context, '/details', arguments: {'userId': '123'}, );
// Get arguments final args = ModalRoute.of(context)!.settings.arguments as Map;
// Return data final result = await Navigator.push( context, MaterialPageRoute(builder: (_) => SelectionScreen()), );
// Pop with result Navigator.pop(context, selectedValue);
HTTP and API import 'package:http/http.dart' as http; import 'dart:convert';
class ApiService { final String baseUrl = 'https://api.example.com';
Future> fetchUsers() async {
final response = await http.get(Uri.parse('$baseUrl/users'));
if (response.statusCode == 200) {
final List<dynamic> data = json.decode(response.body);
return data.map((json) => User.fromJson(json)).toList();
} else {
throw Exception('Failed to load users');
}
}
Future
if (response.statusCode == 201) {
return User.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to create user');
}
} }
// Model with JSON serialization class User { final String id; final String name; final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map
Map
Best Practices Dart Use const constructors when possible Leverage null safety Use final for immutable values Prefer async/await over .then() Use extensions for utility methods Follow Effective Dart guidelines Flutter Keep widgets small and focused Use const widgets for optimization Avoid rebuilding entire trees Implement proper state management Handle errors gracefully Test widgets thoroughly Use keys when needed Performance Use ListView.builder for long lists Implement pagination Cache network images Minimize widget rebuilds Use const constructors Profile app performance Lazy load resources Anti-Patterns
❌ Large widget trees ❌ State in StatelessWidget ❌ Not disposing controllers ❌ Ignoring null safety ❌ Synchronous I/O in UI ❌ No error handling ❌ Hard-coded strings
Resources Dart: https://dart.dev/ Flutter: https://flutter.dev/ Pub.dev: https://pub.dev/ Flutter Widget Catalog: https://flutter.dev/docs/development/ui/widgets Effective Dart: https://dart.dev/guides/language/effective-dart