## 新增功能 - 实时搜索:支持书名和作者的模糊搜索,300ms防抖优化 - Provider状态管理:使用ChangeNotifier模式管理搜索状态 - 搜索页面:完整的搜索UI,包括空状态、搜索中、无结果和结果列表 - 智能交互:一键清空搜索、焦点管理、状态同步 ## 技术实现 - SearchProvider:防抖搜索、状态管理、多字段匹配 - SearchPage:StatefulWidget管理、控制器协调、生命周期优化 - 状态同步:TextEditingController与Provider协调,避免循环更新 - 用户体验:即时反馈、智能清空、页面状态重置 ## 代码质量 - Flutter分析零警告 - 完整的代码注释和文档 - 内存安全:正确的资源清理 - 性能优化:防抖机制和精确UI重建 ## 文档完善 - Provider状态管理学习指南 - 搜索功能开发实战总结 - 顶部导航组件开发总结 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
8.8 KiB
8.8 KiB
Provider状态管理学习指南
📚 什么是Provider?
Provider是Flutter官方推荐的状态管理解决方案,它提供了一种简单、高效的方式来在应用中共享和传递数据。
核心概念
- Provider: 数据提供者,封装状态数据
- Consumer: 数据消费者,监听数据变化并重建UI
- ChangeNotifier: 状态变化通知器,当数据改变时通知监听者
🎯 为什么需要状态管理?
问题场景
// 问题:多个页面需要共享搜索状态
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
String searchText = ''; // 局部状态,无法跨页面共享
return AppHeader(onSearchPressed: () {
// 无法将搜索文本传递给其他页面
});
}
}
class SearchPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 无法获取首页的搜索状态
return Text('搜索结果');
}
}
Provider解决方案
// 解决方案:使用Provider全局共享状态
class SearchProvider extends ChangeNotifier {
String _searchText = '';
List<Book> _searchResults = [];
String get searchText => _searchText;
List<Book> get searchResults => _searchResults;
void updateSearchText(String text) {
_searchText = text;
notifyListeners(); // 通知所有监听者重建
}
void performSearch() {
// 执行搜索逻辑
_searchResults = _searchBooks(_searchText);
notifyListeners();
}
}
🔧 Provider使用步骤
步骤1: 添加依赖
dependencies:
flutter:
sdk: flutter
provider: ^6.0.5 # 添加provider依赖
步骤2: 创建状态管理类
import 'package:flutter/foundation.dart';
class SearchProvider extends ChangeNotifier {
// 私有状态变量
String _searchQuery = '';
bool _isSearching = false;
List<Book> _results = [];
// 公共getter方法
String get searchQuery => _searchQuery;
bool get isSearching => _isSearching;
List<Book> get results => _results;
// 状态更新方法
void updateQuery(String query) {
_searchQuery = query;
notifyListeners(); // 通知UI更新
}
void searchBooks(String query) {
_isSearching = true;
notifyListeners();
// 模拟异步搜索
Future.delayed(const Duration(milliseconds: 500), () {
_results = _performSearch(query);
_isSearching = false;
notifyListeners();
});
}
void clearSearch() {
_searchQuery = '';
_results.clear();
notifyListeners();
}
// 私有搜索方法
List<Book> _performSearch(String query) {
if (query.isEmpty) return [];
// 实际搜索逻辑
return [];
}
}
步骤3: 在应用根部提供Provider
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => SearchProvider(),
child: const ReadfulApp(),
),
);
}
步骤4: 在UI中消费Provider数据
// 方法1: 使用Consumer Widget
Consumer<SearchProvider>(
builder: (context, searchProvider, child) {
return Text('搜索词: ${searchProvider.searchQuery}');
},
)
// 方法2: 使用Provider.of
TextButton(
onPressed: () {
final searchProvider = Provider.of<SearchProvider>(context, listen: false);
searchProvider.updateQuery('Flutter');
},
child: Text('搜索'),
)
// 方法3: 使用Selector(性能优化)
Selector<SearchProvider, List<Book>>(
selector: (context, provider) => provider.results,
builder: (context, results, child) {
return ListView.builder(
itemCount: results.length,
itemBuilder: (context, index) {
return BookTile(book: results[index]);
},
);
},
)
🎨 实际应用:搜索功能实现
搜索状态管理
class SearchProvider extends ChangeNotifier {
String _query = '';
List<Book> _filteredBooks = [];
List<Book> _allBooks = []; // 数据源
// Getters
String get query => _query;
List<Book> get filteredBooks => _filteredBooks;
bool get hasResults => _filteredBooks.isNotEmpty;
bool get isEmpty => _query.isEmpty;
// 初始化数据
void loadBooks(List<Book> books) {
_allBooks = books;
_filteredBooks = books;
notifyListeners();
}
// 更新搜索查询
void updateQuery(String newQuery) {
_query = newQuery.toLowerCase();
_filterBooks();
notifyListeners();
}
// 过滤书籍
void _filterBooks() {
if (_query.isEmpty) {
_filteredBooks = List.from(_allBooks);
} else {
_filteredBooks = _allBooks.where((book) {
return book.title.toLowerCase().contains(_query) ||
book.author.toLowerCase().contains(_query) ||
book.description.toLowerCase().contains(_query);
}).toList();
}
}
// 清空搜索
void clearSearch() {
_query = '';
_filteredBooks = List.from(_allBooks);
notifyListeners();
}
}
搜索页面UI
class SearchPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// 搜索输入框
_buildSearchBar(context),
// 搜索结果
Expanded(
child: Consumer<SearchProvider>(
builder: (context, provider, child) {
if (provider.isEmpty) {
return _buildEmptyState();
} else if (provider.hasResults) {
return _buildResultsList(provider.filteredBooks);
} else {
return _buildNoResults();
}
},
),
),
],
),
);
}
Widget _buildSearchBar(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
child: TextField(
onChanged: (value) {
Provider.of<SearchProvider>(context, listen: false)
.updateQuery(value);
},
decoration: InputDecoration(
hintText: '搜索书名、作者或内容...',
prefixIcon: const Icon(Icons.search),
suffixIcon: Consumer<SearchProvider>(
builder: (context, provider, child) {
return provider.query.isNotEmpty
? IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
Provider.of<SearchProvider>(context, listen: false)
.clearSearch();
},
)
: const SizedBox.shrink();
},
),
),
),
);
}
}
💡 Provider最佳实践
1. 性能优化
// ❌ 错误:每次重建都执行复杂计算
Consumer<MyProvider>(
builder: (context, provider, child) {
return HeavyComputationWidget(data: provider.complexData);
},
)
// ✅ 正确:使用Selector优化
Selector<MyProvider, ComputedData>(
selector: (context, provider) => provider.computedData,
builder: (context, data, child) {
return HeavyComputationWidget(data: data);
},
)
2. 合理拆分Provider
// ❌ 错误:一个Provider管理太多状态
class AppProvider extends ChangeNotifier {
// 搜索状态
String searchQuery = '';
List<Book> searchResults = [];
// 用户状态
User? currentUser;
bool isLoggedIn = false;
// 主题状态
bool isDarkMode = false;
Color accentColor = Colors.blue;
}
// ✅ 正确:按功能拆分Provider
class SearchProvider extends ChangeNotifier { /* 搜索相关 */ }
class UserProvider extends ChangeNotifier { /* 用户相关 */ }
class ThemeProvider extends ChangeNotifier { /* 主题相关 */ }
3. 错误处理
class SearchProvider extends ChangeNotifier {
bool _isLoading = false;
String? _errorMessage;
bool get isLoading => _isLoading;
String? get errorMessage => _errorMessage;
Future<void> searchAsync(String query) async {
_isLoading = true;
_errorMessage = null;
notifyListeners();
try {
final results = await _apiService.search(query);
_updateResults(results);
} catch (e) {
_errorMessage = e.toString();
} finally {
_isLoading = false;
notifyListeners();
}
}
}
🎯 学习总结
关键概念
- ChangeNotifier: 状态管理基类,提供notifyListeners()方法
- Consumer: 监听Provider变化并自动重建UI
- Selector: 性能优化的Consumer,只监听特定数据变化
- Provider.of: 手动获取Provider实例的方式
使用场景
- ✅ 全局状态: 用户信息、主题设置
- ✅ 页面间共享: 搜索状态、购物车数据
- ✅ 复杂数据: 表单状态、异步加载状态
注意事项
- 避免在build方法中创建Provider实例
- 合理使用listen参数控制是否需要重建
- 及时dispose防止内存泄漏
- 使用Selector优化UI重建性能
下一步:我们将使用Provider来实现Readful的搜索功能!