Jetpack for Flutter
一套受Android Jetpack启发的抽象和实用工具,用于帮助管理Flutter应用程序的状态。
特点
LiveData
状态持有者和更改通知者,它还允许读取当前值。
如果您完全使用Stream和响应式编程,您可能不需要这个。但如果您想编写命令式代码来更新状态,这应该会有所帮助。
EventQueue
用于将短暂状态推送到UI并在处理后清除。适用于在ViewModel中触发吐司/弹出窗口。
ViewModel
业务逻辑容器,它向UI公开状态、事件方法并与应用程序的其余部分通信。
用法
创建您的ViewModel并使用LiveData公开状态。
import 'package:jetpack/jetpack.dart';
class CounterViewModel extends ViewModel {
final MutableLiveData<int> _counter = MutableLiveData(0);
LiveData<int> get counter => _counter;
void increment() {
_counter.value++;
}
}
您可以像下面描述的那样,使用BuildContext在任何地方访问您的CounterViewModel。
@override
Widget build(BuildContext context) {
final CounterViewModel viewModel = context.viewModelProvider.get();
}
您可以使用LiveDataBuilder来消耗LiveData。
LiveDataBuilder<int>(
liveData: viewModel.counter,
builder: (BuildContext buildContext, int count) =>
Text('$count'),
)
)
您可以通过直接调用ViewModel上的方法,将UI事件传递给ViewModel。
FloatingActionButton(
onPressed: viewModel.increment,
//...
)
入门
此库尚未发布。在此之前,请考虑复制viewmodel.dart和livedata.dart。
为您的应用创建一个ViewModelFactory。
class MyAppViewModelFactory extends ViewModelFactory {
const MyAppViewModelFactory();
@override
T create<T extends ViewModel>() {
if (T == HomeViewModel) {
return HomeViewModel() as T;
}
throw Exception("Unknown ViewModel type");
}
}
待定:为像get_it这样的依赖注入框架的用户添加说明。
在您的应用程序的根目录提供您的ViewModelFactory。
void main() {
const MyAppViewModelFactory viewModelFactory = MyAppViewModelFactory();
runApp(const MyApp(viewModelFactory: viewModelFactory));
}
class MyApp extends StatelessWidget {
final ViewModelFactory viewModelFactory;
const MyApp({super.key, required this.viewModelFactory});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ViewModelFactoryProvider(
viewModelFactory: viewModelFactory,
child: MaterialApp(
title: 'Flutter App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(title: 'Home Page'),
),
);
}
}
创建一个基础WidgetPage,用`ViewModelScope`包装所有页面内容。
abstract class Page extends StatelessWidget {
const Page({super.key});
Widget buildContent(BuildContext context);
@override
Widget build(BuildContext context) {
return ViewModelScope(builder: buildContent);
}
}
如果您已经有一个所有页面的基类,那么可以使用ViewModelScope像上面那样包装内容。
为什么是另一个状态管理库?
这些是在Android生态系统中经过5年以上验证的模式。即使采用了全新的UI框架——Jetpack Compose,它们仍然保持完好。这些抽象由于**低耦合**和**灵活性**而能够经受住变化。
Flutter中现有的解决方案,如bloc、provider等,默认将逻辑持有者限制为仅发出一个状态流,并需要额外的样板代码来“选择”UI想要响应的状态片段。
class MyLogicHolder: LogicHolder<StateModel>
有时,我们希望公开多个相关的状态流,但它们以不同的频率变化/发出。直接从ViewModel公开它们,而无需编写选择器等样板代码,非常方便且没有额外开销。
class MyViewModel: ViewModel {
final MutableLiveData<int> _counter = MutableLiveData(0);
final MutableLiveData<boolean> _isModified = MutableLiveData(false);
LiveData<int> get counter => _counter;
LiveData<int> get isModified => _isModified;
void increment() {
_counter.value++;
_isModified.value = true;
}
}
这使我们能够按照UI的消费方式来组织和传播状态,并尽量减少不必要的Widget重建。
您也可以使用Future和Stream将状态公开给UI。由您**选择**。
class ProductViewModel: ViewModel {
//
Future<ProductDetails> productDetails = await fetchProductDetails();
Stream<bool> isAddedToCart = cartRepository.isAddedToCart(_productId);
}
并使用FutureBuilder和StreamBuilder来监听和更新UI。
无需创建额外的模型来将UI事件传递给ViewModel。只需直接调用方法即可。
ElevatedButton(
onPressed: viewModel.increment
//...
)