flutter-持久化储存、JSON与对象转化

前言

在开发过程中,无论是用户信息保存,还是网络数据保存,难免会用到本地操作,在flutter中有一款 key-value 形式的本地操作(就像 iosNSUserDefaults似的)

另外,这里也介绍下JSON与对象间的相互转化

JOSN快速生成各种语言Model入口

demo地址(内容在fileManager文件夹中,可以替换main中注释尝试效果)

tips:如果存放大量数据,需要关系型数据库,那么可以搜其他资源

持久化储存(key-value)

导入shared_preferences

这个持久化储存用的仓库,是flutter的团队开发的,叫shared_preferences,但他是以三方仓库存在的,因此需要手动导入

flutter pub add shared_preferences
复制代码

导入之后就可以直接 import 直接使用了(一般使用提示导入)

import 'package:shared_preferences/shared_preferences.dart';
复制代码

SharedPreferences介绍

SharedPreferences为一个单例,并且是一个 Future异步函数,因此获取的时候也需要 Future异步函数调用获取,通过 await 的方式获取到单例(前面有讲到过 Future)

大致原理:与其他缓存三方原理类似,文件信息保存的时候内存一份、本地一份,在初始化的时候会一次性读取所有数据到内存

可以明显看出优缺点:访问速度快,内存占用大,适合小信息保存

如果存放大量数据,或者需要存放复杂的数据,那么需要选择其他数据库

数据库:对于关系型数据库SQLite、Core Data、GreenDao等;对于非关系型数据库,可选有Realm、UnQLite等;对于Key/Value存储,有比如Redis、Berkeley DB、Level DB等

可以根据自己的需要选择封装好的数据库,手机端一般是SQLiteRealm

SharedPreferences读写操作

存放数据

通过传递keyvalue,能存放各种基本数据,发现没有存放对象的(不后面介绍)

//这里仅仅通过泛型演示,实际上用哪个调用哪个即可,可以自己封装一下
static saveInfo<T>(String key, T value) async {
    //需要通过await获取单例对象
    final manager =  await SharedPreferences.getInstance();
    //默认的使用只有如下几种
    manager.setBool(key, value as bool);
    manager.setDouble(key, value as double);
    manager.setInt(key, value as int);
    manager.setString(key, value as String);
    manager.setStringList(key, value as List<String>);
}
复制代码

读取数据

通过传递key值,可以直接调用对应的get方法即可,可以发现也没有读取对象的(后面介绍)

//这里仅仅通过泛型演示,实际上用哪个调用哪个即可,可以自己封装一下
static Future<T> readInfo<T>(String key) async {
    final manager = await SharedPreferences.getInstance();
    return manager.getString(key) as T;
    return manager.getBool(key) as T;
    return manager.getDouble(key) as T;
    return manager.getInt(key) as T;
    return manager.getString(key) as T;
    return manager.getStringList(key) as T;
}
复制代码

删除数据

删除不多说了,传一个key就删了

static remove(String key) async {
  final manager =  await SharedPreferences.getInstance();
  manager.remove(key);
}
复制代码

json与对象相互转化与存放对象

前面也看到了,shared_preferences没有存放对象的本事,那我们就存放对象变成 存放json字符串即可

因此,需要了解的步骤就是 json与对象的相互转化

flutter中目前还没有看到反射机制,因此还无法友好的一键式转化,目前只能以 Map作为纽带jsonMap之间的相互转化,对象所属类负责 对象Map之间的相互转化

json和Map之间的转化

通过系统预制的 convert 库,来实现转化过程

通过 jsonEncodeMap 转化成 jsonString

final userMap = {
    name: "Marshal",
    age: 20
}

//将map转化成 jsonString
final jsonString = jsonEncode(userMap);
复制代码

通过 jsonDecodejsonString 转化成 Map

final jsonString = "{"name": "Marshal", "age": 20}";

//jsonString 转化成 Map
final jsonMap = jsonDecode(jsonString);
复制代码

对象和Map之间的转化

UserInfo类为例,创建两个方法(每个需要保存的类都要实现这两个方法)

jsonMap转化为对象:通过命名式构造方法,可以将传过来的 jsonMap 转化为 本对象

对象转化为jsonMap:通过对象方法或者类方法,可以将本类创建的对象,转化为 Map

//选中类名,摁着 ctl + enter,生成 Constructor,选择需要默认初始化的属性,可以生成带参构造方法
class UserInfo {
  String name;
  int age;

  UserInfo(this.name, this.age);

  //命名式构造方法,也可以是用工厂构造方法
  UserInfo.fromJson(Map<String, dynamic> json): name = json['name'], age = json['age'];

  //如果想写成协议,归档(json和对象互转时,为了使用方便)时,可以继承协议,那么可以用普通方法,而不是构造方法
  Map<String, dynamic> toJson() =>
      {'name': name, 'age': age};
}
复制代码

对象和json的间接相互转化

对象间接转化为json字符串,以UserInfo为例

final userInfo = UserInfo("Marshal", 20);

//将 UserInfo 转化为 jsonMap
final userMap = userInfo.toJson();

//然后调用 jsonEncode 将 map 转化成 jsonString
final jsonString = jsonEncode(userMap);

//jsonEncode默认只能将map转化成json,因此需要利用二个回调,将对象转化为map,然后才进行的转化
//实际和上面一样
final jsonString2 = jsonEncode(value,
  toEncodable: (Object? value) => value is UserInfo
      ? value.toJson()
      : throw UnsupportedError('Cannot convert to JSON: $value'));
复制代码

json字符串间接转化为对象,以UserInfo为例

final jsonString = "{"name": "Marshal", "age": 20}";

//将 jsonString 转化为 jsonMap
final jsonMap = jsonDecode(jsonString); //转化成 Map

//将 jsonMap 转化为 UserInfo
final userInfo = UserInfo.fromJson(jsonMap);
复制代码

SharedPreferences存取对象

存放对象,将前面的步骤都结合起来,存放对象转化的json字符串

static saveObject(String key, UserInfo value) async {
  final manager =  await SharedPreferences.getInstance();

  //实际上可以将 UserInfo设置为泛型约束,继承(or多继承)某个类或者实现某一个接口,通过该接口调用toJson方法
  //将一个类转化为jsonString
  //此过程需要调用对应类的 toJson 方法,现将类信息放到 Map 中,然后在转化成json
  final userMap = value.toJson();
  //然后调用jsonEncode将map转化成 jsonString
  final jsonString = jsonEncode(userMap);

  //jsonEncode默认只能将map转化成json,因此需要利用二个回调,将对象转化为map,然后才进行的转化
  //实际和上面一样
  final jsonString2 = jsonEncode(value,
      toEncodable: (Object? value) => value is UserInfo
          ? value.toJson()
          : throw UnsupportedError('Cannot convert to JSON: $value'));

  if (jsonString.isEmpty) return;
  manager.setString(key, jsonString);
  log('jsonEncode --' + jsonString);
}
复制代码

读取对象,将前面的步骤都结合起来,读取json字符串转化的对象

static Future<dynamic> readObject(String key) async {
  final manager =  await SharedPreferences.getInstance();
  final jsonString = manager.getString(key);
  if (jsonString != null) {
    final jsonMap = jsonDecode(jsonString); //转化成 Map
    log('jsonDecode --' + jsonMap.toString());
    //实际使用中,可以直接返回 Map 集合,从外面给类赋值,以减少耦合
    return UserInfo.fromJson(jsonMap); //根据根据命名式构造方法转化
  }
  return null;
}
复制代码

tips: FileManagerEx(存取对象改进版,目前无法解决构造方法的问题,只能稍微限制一下,仅供参考哈)

最后

赶快测试一下吧,这个 shared_preferences只适合存放少量数据,例如用户基本信息,搜索信息等,如果需要大量数据,或者关系型,可以切换其他的哈

这个 对象和json互转 才是本章最主要的介绍

Guess you like

Origin juejin.im/post/7074571152500211719