使用状态管理方案保存和恢复状态
- Provider
- 实现思路:
- 创建一个继承自
ChangeNotifier
的模型类,用于存储需要在方向切换时保持的状态数据。例如,假设我们有一个计数器应用,需要在方向切换时保持计数器的值。
- 使用
ChangeNotifierProvider
将模型类提供给整个应用或相关的子树。这样,当状态改变时,依赖该状态的组件会自动重建。
- 关键代码片段:
// 定义模型类
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// 在应用中使用Provider
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
),
);
}
// 在组件中使用状态
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of<CounterModel>(context);
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'${counter.count}',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => counter.increment(),
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
- Bloc
- 实现思路:
- 定义事件(Event)和状态(State)类。例如,对于计数器应用,事件可以是
IncrementEvent
,状态可以是CounterState
,包含计数器的值。
- 创建一个Bloc类,处理事件并生成新的状态。
- 使用
BlocProvider
将Bloc提供给应用或相关子树,BlocBuilder
根据Bloc的状态来重建组件。
- 关键代码片段:
// 定义事件
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
// 定义状态
class CounterState {
final int count;
CounterState(this.count);
}
// 创建Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(CounterState(0));
@override
Stream<CounterState> mapEventToState(CounterEvent event) async* {
if (event is IncrementEvent) {
yield CounterState(state.count + 1);
}
}
}
// 在应用中使用Bloc
void main() {
runApp(
BlocProvider(
create: (context) => CounterBloc(),
child: MyApp(),
),
);
}
// 在组件中使用状态
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
return Text(
'${state.count}',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => counterBloc.add(IncrementEvent()),
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
优化渲染性能避免卡顿
- 使用
AutomaticKeepAliveClientMixin
- 实现思路:对于有状态组件,当方向切换时,默认会重建。如果组件中有一些复杂的初始化操作,重建会导致性能问题。使用
AutomaticKeepAliveClientMixin
可以让组件在方向切换时保持存活,避免不必要的重建。
- 关键代码片段:
class MyKeepAliveWidget extends StatefulWidget {
@override
_MyKeepAliveWidgetState createState() => _MyKeepAliveWidgetState();
}
class _MyKeepAliveWidgetState extends State<MyKeepAliveWidget> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
// 这里进行组件的构建
return Container();
}
}
- 缓存数据
- 实现思路:如果组件依赖一些需要从网络或数据库获取的数据,可以在方向切换前缓存这些数据,切换后直接使用缓存数据,避免重复获取。例如,可以使用
MemoryCache
等简单的缓存机制。
- 关键代码片段:
class DataCache {
static Map<String, dynamic> cache = {};
static void cacheData(String key, dynamic value) {
cache[key] = value;
}
static dynamic getCachedData(String key) {
return cache[key];
}
}
// 在获取数据的方法中使用缓存
Future<dynamic> fetchData() async {
final cachedData = DataCache.getCachedData('myDataKey');
if (cachedData!= null) {
return cachedData;
}
// 从网络或数据库获取数据
final newData = await someDataFetchingFunction();
DataCache.cacheData('myDataKey', newData);
return newData;
}
- 减少不必要的重建
- 实现思路:使用
const
构造函数创建不可变的组件,这样在方向切换时,如果组件的属性没有改变,Flutter不会重建该组件。同时,合理使用AnimatedBuilder
等组件,只在需要动画更新的部分进行重建,而不是整个组件树。
- 关键代码片段:
// 使用const构造函数
const MyConstWidget = Text('This is a const widget');
// 使用AnimatedBuilder
class MyAnimatedWidget extends StatefulWidget {
@override
_MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();
}
class _MyAnimatedWidgetState extends State<MyAnimatedWidget> with SingleTickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..repeat();
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Transform.rotate(
angle: _controller.value * 2 * pi,
child: child,
);
},
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
}
}