Flutter Best Practices
This section will introduce best practices and coding standards in Flutter development.
Code Standards
Naming Conventions
| Type | Rules | Example |
|---|---|---|
| Class name | UpperCamelCase | MyHomePage |
| Functions/Variables | lowerCamelCase | userName, getData |
| Constants | Upper Camel Case + k Prefix | kMaxCount |
| File | Lowercase + Underscore | my_home_page.dart |
Example: Correct Naming
// Class name - UpperCamelCase
class UserProfilePage extends StatelessWidget {}
// Function - lowerCamelCase
void fetchUserData() {}
// Variable - lowerCamelCase
String userName = 'Zhang San';
// Constants - k prefix
const int kMaxRetryCount = 3;
const String kAppName = 'My App';
// Enum - UpperCamelCase
enum AppState { loading, success, error }
// File name - snake_case
// user_profile_page.dart
class UserProfilePage extends StatelessWidget {}
// Function - lowerCamelCase
void fetchUserData() {}
// Variable - lowerCamelCase
String userName = 'Zhang San';
// Constants - k prefix
const int kMaxRetryCount = 3;
const String kAppName = 'My App';
// Enum - UpperCamelCase
enum AppState { loading, success, error }
// File name - snake_case
// user_profile_page.dart
Performance Optimization
1. Avoid unnecessary rebuilds
Example: Using const Constructor
// Recommended: use const to reduce rebuilds
const Text('Hello') // Will not rebuild
const SizedBox(width: 10)
// Avoid: every build creates a new object
Text('Hello') // Will rebuild
// Use const in lists
ListView(
children: const [
Text('A'),
Text('B'),
Text('C'),
],
)
const Text('Hello') // Will not rebuild
const SizedBox(width: 10)
// Avoid: every build creates a new object
Text('Hello') // Will rebuild
// Use const in lists
ListView(
children: const [
Text('A'),
Text('B'),
Text('C'),
],
)
2. Use keys to optimize list performance
Example: Using Keys Correctly
// Add unique keys to list items
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(items[index].id), // Use unique identifiers as keys
title: Text(items[index].name),
);
},
)
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(items[index].id), // Use unique identifiers as keys
title: Text(items[index].name),
);
},
)
3. Lazy Loading List Items
Example: Using ListView.builder
// Recommended: use builder for lazy loading
ListView.builder(
itemCount: 1000, // Must use for large lists
itemBuilder: (context, index) {
return ListTile(title: Text('Item $index'));
},
)
// Avoid: using children to build large lists
ListView(
children: List.generate(1000, (i) => Text('Item $i')),
)
ListView.builder(
itemCount: 1000, // Must use for large lists
itemBuilder: (context, index) {
return ListTile(title: Text('Item $index'));
},
)
// Avoid: using children to build large lists
ListView(
children: List.generate(1000, (i) => Text('Item $i')),
)
Project Structure
Example: Recommended Project Structure
// lib/
// ├── main.dart # entry file
// ├── app.dart # app configuration
// ├── core/ # core functionality
// │ ├── constants/ # constants
// │ ├── theme/ # theme
// │ ├── utils/ # utility classes
// │ └── extensions/ # extensions
// ├── data/ # data layer
// │ ├── models/ # data models
// │ ├── repositories/ # Repositories
// │ └── services/ # Network Services
// ├── domain/ # Domain Layer
// │ └── entities/ # Entities
// ├── presentation/ # Presentation Layer
// │ ├── pages/ # Pages
// │ ├── widgets/ # Widgets
// │ └── providers/ # State Management
// └── routes/ # Routes
// ├── main.dart # entry file
// ├── app.dart # app configuration
// ├── core/ # core functionality
// │ ├── constants/ # constants
// │ ├── theme/ # theme
// │ ├── utils/ # utility classes
// │ └── extensions/ # extensions
// ├── data/ # data layer
// │ ├── models/ # data models
// │ ├── repositories/ # Repositories
// │ └── services/ # Network Services
// ├── domain/ # Domain Layer
// │ └── entities/ # Entities
// ├── presentation/ # Presentation Layer
// │ ├── pages/ # Pages
// │ ├── widgets/ # Widgets
// │ └── providers/ # State Management
// └── routes/ # Routes
Error Handling
Example: Global Error Handling
void main() {
// Global exception capture
FlutterError.onError = (details) {
// Log error
print('Flutter Error: ${details.exception}');
// Report error to server
reportError(details.exception);
};
// Zone exception capture
runZonedGuarded(() {
runApp(const MyApp());
}, (error, stackTrace) {
print('Zone Error: $error');
reportError(error);
});
}
// Global exception capture
FlutterError.onError = (details) {
// Log error
print('Flutter Error: ${details.exception}');
// Report error to server
reportError(details.exception);
};
// Zone exception capture
runZonedGuarded(() {
runApp(const MyApp());
}, (error, stackTrace) {
print('Zone Error: $error');
reportError(error);
});
}
other extensionsFollowing best practices can make code more maintainable, perform better, and reduce bugs in production.