Flutter状态管理

184 阅读1分钟

Provider

Provider是目前官方推荐的全局状态管理工具。

Provider的基本使用

在使用Provider时候,了解三个基本概念

  • ChangeNotifier:数据存在的位置,viewModel继承ChangeNotifier,处理状态变化逻辑。
  • ChangeNotifierProvider:Provider提供创建ChangeNotifier的地方。
  • Consumer、Selector:使用状态。

第一步:创建ChangeNotifier

我们需要一个保存状态的ChangeNotifier

  • 初始化一个searchState,未进行搜索状态。
  • 调用搜索事件方法searchMapEvent,在这个方法内部处理,搜索无结果状态,搜索有结果状态等逻辑。
  • 当状态发生改变时,通过Provider内部apinotifyListeners();通知Consumer更新Widget。
  • 搜索的状态分别:未搜索,搜索有结果,搜索无结果

以下是ViewModel代码:

class SearchViewModel extends ChangeNotifier {

  SearchState searchState = SearchStateNoSearch();
    
  /// 高德地图搜索插件
  final CRMAMapFlutterSearch _flutterSearch = AMapFlutterSearch();

  SearchViewModel() {
    _flutterSearch.onSearchResults().listen((date) {
      ...数据处理...
      /// 更新状态
      searchState = array.isEmpty ? SearchStateEmpty() : SearchStateSuccess<MapSearchResultEntity>(array);
      notifyListeners();
    });
  }

  /// 地图搜索
  void searchMapEvent(SearchMapEvent event) async {
    if (event.keyword.isEmpty) {
      searchState = SearchStateNoSearch();
      notifyListeners();
    } else {
      _flutterSearch.searchTipsWithKey(searchP);
    }
  }

  /// 普通搜索
  void searchCustomEvent(SearchCustomEvent event) async {
    if (event.keyword.isEmpty) {
      searchState = SearchStateNoSearch();
    } else {
      /// 网络请求
    }
    notifyListeners();
  }

}

第二步:给widget树插入ChangeNotifierProvider,创建ChangeNotifier

  • 因为搜索组件在整个app中不光用在地图搜索,也有普通搜索,因此将ChangeNotifierProvider放在最顶层。
  • 采用MultiProvider,方便扩展,可以添加例如:主题色,字体大小等状态变化。
return MultiProvider(
  providers: [
    ChangeNotifierProvider(
      create: (context) => SearchViewModel(),
    ),
  ],
  child: MyApp(),
);

第三步:在搜索页使用Consumer更新Widget状态

  • body中,根据搜索状态不同,显示不同的widget
  • 在textField输入搜索内容,修改ChangeNotifity中搜索状态
Column(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    _topSearchView(),
    Expanded(
      child: Consumer<SearchViewModel>(
        builder: (context, searchVM, child) {
          return _buildBodyBySearchState(searchVM.searchState);
        },
      )
    ),
    _bottomSureView(),
  ],
)
  

_topSearchView() {
  return SizedBox(
      height: 40,
      child: TextField(
        controller: _textEditingController,),
        onChanged: (keyword) {
          var searchVM = context.read<SearchViewModel>();
          searchVM.searchMapEvent(SearchMapEvent(keyword: keyword, city: '广州'));
        },
    ),
  );
}  
  
 
/// 内容状态更新
Widget _buildBodyBySearchState(SearchState state) {
  if (state is SearchStateNoSearch) return _noSearchView();
  if (state is SearchStateEmpty) return _emptyResultView();
  if (state is SearchStateSuccess) return _successResultView(state.searchResults);
  return _noSearchView();
}