Flutter 数据存储 和状态管理的几种方式对比

flutter 项目中 数据的管理是个很重要的环节, 今天这篇博客主要就是讲讲 flutter 中数据的存储和状态管理的几种方式,以及优缺点.

数据存储

  • shared_preferences
  • sqflite
  • redux 和 redux_persist

下面说说各种存储方式的优缺点

shared_preferences

shared_preferences 其实就是个 key-value 的存储方式, 可以做一些开关配置的存储,比如是否首次登陆这种.

优点

存储简单,直接通过 putget key 值来存储和获取.

// 如果_sp已存在,直接返回,为null时创建
  static Future<SharedPreferences> get sp async {
    if (_sp == null) {
      _sp = await SharedPreferences.getInstance();
    }
    return _sp!;
  }

  static Future<bool> save(String key, String value) async {
    Logger.i("save  key = $key , value = $value");
    return (await sp).setString(key, value);
  }

  static dynamic get(String key) async {
    return (await sp).get(key);
  }
缺点

一般都是一些配置的存储, 如果是对象或者数组的存储,就会很麻烦.

sqflite

数据库存储, 一般都是存储对象和数组.

优点

能够存储复杂的数据和数组

缺点

操作麻烦, 要先创建表,管理数据库的版本信息, 以及更新库表操作, 如果不熟练 很容易出错.

代码

dbHelp

var databasesPath = await getDatabasesPath();
    String path = join(databasesPath, '$dbName.db');
//根据数据库文件路径和数据库版本号创建数据库表
    db = await openDatabase(path, version: dbVersion, onConfigure: onConfigure,
        onCreate: (Database db, int version) async {
      var batch = db.batch();
      GlobalConfigDao.createGlobalConfigV1(batch);
      await batch.commit();
      Timer(Duration(seconds: 1), () {
        GlobalConfigDao.insertGlobalConfig(
            GlobalConfigData(fontFamily: 0, themeColor: 1));
      });
    }, onUpgrade: (db, oldVersion, newVersion) async {
      // var batch = db.batch();
      // switch (oldVersion) {
      //   case 1:
      //     WelcomeConfigDao.createWelcomeConfigV2(batch);
      //     break;
      // }
      // await batch.commit();
    });

GlobalConfigDao

static void createGlobalConfigV1(Batch batch) {
    batch.execute('DROP TABLE IF EXISTS globalConfig');
    batch.execute('''CREATE TABLE globalConfig (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    themeColor INTEGER,
    fontFamily INTEGER)''');
  }

redux redux_persist

redux_persist 其实说到底也类似于 shared_preferences, 他也是通过 key 来存储的, 只不过我们可以通过对象的 toJson 方法把对象转成 json,然后 redux_persist 把当前的 json 转成 string 存储到 key 里面去.

存储对象 readConfig

part 'readConfig.g.dart';

@JsonSerializable(explicitToJson: true)
class ReadConfig {
  int textFontIndex;

  int bgColorIndex;

  ReadConfig({this.bgColorIndex: 2, this.textFontIndex: 2});

  factory ReadConfig.fromJson(Map<String, dynamic> json) =>
      _$ReadConfigFromJson(json);

  Map<String, dynamic> toJson() => _$ReadConfigToJson(this);

  // 命名构造函数
  ReadConfig.empty();
}

readConfigRedux


class UpdateReaderConfigAction {
  ReadConfig readConfig;

  UpdateReaderConfigAction(this.readConfig);
}

ReadConfig _update(ReadConfig readConfig, action) {
  readConfig = action.readConfig;
  return readConfig;
}

final ReadConfigReducer = combineReducers<ReadConfig>([
  TypedReducer<ReadConfig, UpdateReaderConfigAction>(_update),
]);

state


class DzState {

  ReadConfig readConfig;

  DzState(
      {
      this.readConfig,});

  static DzState fromJson(dynamic json) => json != null
      ? DzState(
          readConfig: ReadConfig.fromJson(json["readConfig"] ??
              ReadConfig(bgColorIndex: 2, textFontIndex: 2).toJson()))
      : DzState.empty();

  dynamic toJson() => {
        "readConfig": readConfig,
      };

  static DzState empty() {
    return DzState(
        readConfig: ReadConfig(bgColorIndex: 2, textFontIndex: 2),
        );
  }
}

DzState appReducer(DzState state, action) {
  return new DzState(
      readConfig: ReadConfigReducer(state.readConfig, action));
}

在 main.dart 中调用

final persistor = Persistor<DzState>(
    storage: FlutterStorage(),
    serializer: JsonSerializer<DzState>(DzState.fromJson),
  );

  // Load initial state
  final initialState = await persistor.load();

  final store = Store<DzState>(
    appReducer,
    initialState: initialState ?? DzState.empty(),
    middleware: [persistor.createMiddleware()],
  );
优点

既可以存简单的 key-value 的值, 也可以存储对象和数组.

缺点

创建一个对象比较复杂, 很容易初始化出错, 而且没法给对象中的单独变量修改,要修改的时候 必须把当前对象获取到,然后修改变量的值, 然后把整个对象给修改掉.


ReadConfig config = DzStore.getStore().state.readConfig;

config.textFontIndex = value.toInt();
DzStore.getStore().dispatch(UpdateReaderConfigAction(config));

数据状态管理

  • redux
  • provider
  • bloc

数据的状态管理 一般用这三个.下面分别说说三个的优缺点.

redux

优点

只要 redux 里面的数值改变, 引用的地方都会刷新,比如启动多个页面 其中一个页面头像和昵称修改,那么回退回去后,页面的头像和昵称也会发生修改.数据及时同步

缺点

只要用 StoreBuilder<DzState>(builder: (storeContext, store) 的地方, 都会重新刷新,很容易造成没必要的性能浪费.

provider

优点

只要 provider 里面的数据发生改变, 引用当前的 provider 的页面才会重新刷新

缺点

如果当前 provider 有多个状态, 那么只要修改其中一个状态, 那页面也是都会刷新.也容易造成性能的浪费.

bloc

bloc 可以说是集成了 redux 和 provider 的所有优点, 并且优化了他们的缺点.

bloc 定义事件, 每个事件一个 state, 只要处理返回的对象 state 就行了,就减少了性能的浪费, 减少了没必要的刷新.

后面就在实战项目中来体现.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值