在 Flutter 中简单实现 LiveData
如果你是一名 Android 开发者,LiveData 一定不陌生 ,它和 ViewModel 组合便可以构成简单的 MVVM 模式,而且是生命周期敏感的,不会造成不必要内存泄漏。
那么在 Flutter 中是否也能使用到 LiveData 呢?很可惜,官方并没有给出相关 API。但是使用现有的官方 API 和第三方 API 还是可以简单实现的。
首先我们总结下 LiveData 和 ViewModel 的几个特点:
- LiveData 可自动通知其上的观察者其值的改变。
- LiveData 会监听 Activity 或 Fragment 的生命周期,若视图已销毁,则不会通知其上的观察者(observeForeve除外)。
- ViewModel 用于业务逻辑和 UI 解耦,可复用。
LiveData 实现
1 2 3 4 5 6 7 8 9 10 11 12
| import 'package:flutter/material.dart';
class LiveData<T> with ChangeNotifier { T _data;
T get value => _data;
set value(T data) { _data = data; notifyListeners(); } }
|
就是这么简单,一个 Flutter 版的 LiveData 已经实现了。
仅仅使用 LiveData 还不够优雅,我们仍需手动调用 setState
方法去触发 Widget 刷新,接下来定义一个 LiveDataWidget 类,用于监听 LiveData 并自动更新其中的 Widget。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import 'package:flutter/material.dart'; import 'package:provider/provider.dart';
class LiveDataWidget<T extends LiveData> extends StatelessWidget { LiveDataWidget({Key key, @required this.data, @required this.builder}) : super(key: key);
final T data;
final Widget Function(BuildContext context, T value, Widget child) builder;
@override Widget build(BuildContext context) { return ChangeNotifierProvider<T>( builder: (_) { return data; }, child: Consumer(builder: builder), ); } }
|
这里使用到了 provider
中的 ChangeNotifierProvider
和 Consumer
,这样一个简单的组合就能做到当 data
发生变化,Consumer 就会重新构建其中的 Widget。
ViewModel 实现
ViewModel
并没有固定的实现,可以在实际使用中自行定义。
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| import 'package:bili_livedata/bili_livedata.dart'; import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } }
mixin HomePageViewModel { final LiveData<int> counterLiveData = LiveData();
void counterAdd(int add) { if (counterLiveData.value == null) { counterLiveData.value = 0; } else { counterLiveData.value = counterLiveData.value + add; } } }
class MyHomePage extends StatelessWidget with HomePageViewModel { MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), LiveDataWidget<LiveData<int>>( data: counterLiveData, builder: (context, value, _) { return Text(value.value.toString()); }), ], ), ), floatingActionButton: FloatingActionButton( onPressed: () { counterAdd(2); }, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }
|
结合上面的代码再来回顾一下我们上面结合的三点:
LiveData 可自动通知其上的观察者其值的改变。
已实现 ,通过 ChangeNotifier 和 ChangeNotifierProvider 实现。
LiveData 会监听 Activity 或 Fragment 的生命周期,若视图已销毁,则不会通知其上的观察者(observeForeve除外)。
已实现,ChangeNotifierProvider 内部会在 dispose 方法会去调用 ChangeNotifier 的 dispose 方法,所以当 页面销毁,ChangeNotifier(即 LiveData)上的监听者会被移除,不会造成内存泄漏。
ViewModel 用于业务逻辑和 UI 解耦,可复用。
已实现,观察 HomePageViewModel,可以发现,业务逻辑都其中在其中,MyHomePage 只负责取 HomePageViewModel 中的 counterLiveData 值做展示,做到了业务和视图分离。另外 HomePageViewModel 作为一个 mixin,是可以被复用的,flutter 中也支持 with 多个 mixin。
以上,简单的 Flutter 版 LiveData 就已经实现。
总结
不管是否使用 LiveData,重要的是学习其中的设计思想:
- 业务层视图层低耦合
- 业务层高复用
- UI 生命周期管理
另外将业务分离可以更有利于单元测试。