跳转至

GetStorage 轻量级本地存储

GetStorage 是 GetX 官方配套的轻量级键值对存储方案,适合 Flutter 移动端数据持久化。


1. 为什么选择 GetStorage?

方案 适用场景 优点 缺点
GetStorage 轻量数据、简单键值对 轻量、无依赖、同步API 不适合复杂结构
SharedPreferences 简单配置 原生支持 类型限制
Hive 复杂数据结构 高性能、支持加密 需要初始化
Sqflite 结构化数据 SQL 查询能力 学习成本高

GetStorage 特点:同步读写无异步回调轻量级无需初始化


2. 安装

# pubspec.yaml
dependencies:
  get_storage: ^2.1.1
flutter pub get

3. 初始化(App 入口)

main.dart 入口初始化:

import 'package:get_storage/get_storage.dart';

void main() async {
  await GetStorage.init();  // 必须异步初始化
  runApp(MyApp());
}

4. 基础用法

4.1 写入数据

// 存储字符串
GetStorage().write('name', 'Luke');

// 存储数字
GetStorage().write('age', 25);

// 存储布尔值
GetStorage().write('isDark', true);

// 存储列表
GetStorage().write('tags', ['flutter', 'getx', 'dart']);

// 存储 Map
GetStorage().write('user', {
  'id': 1,
  'name': 'Luke',
  'email': 'luke@example.com'
});

4.2 读取数据

// 读取字符串,默认值 ''
String name = GetStorage().read('name') ?? 'default';

// 读取数字,默认值 0
int age = GetStorage().read('age') ?? 0;

// 读取布尔值,默认值 false
bool isDark = GetStorage().read('isDark') ?? false;

// 读取列表
List tags = GetStorage().read('tags') ?? [];

// 读取 Map
Map? user = GetStorage().read('user');

4.3 删除数据

// 删除单个键
GetStorage().remove('name');

// 清空所有数据
GetStorage().erase();

4.4 检查键是否存在

bool exists = GetStorage().hasData('name');

5. 进阶用法:Service 封装

推荐封装为 GetxService,方便依赖注入:

class StorageService extends GetxService {
  late final GetStorage _box;

  Future<StorageService> init() async {
    await GetStorage.init();
    _box = GetStorage();
    return this;
  }

  // 通用读写方法
  T? read<T>(String key) => _box.read<T>(key);

  Future<void> write(String key, dynamic value) async {
    await _box.write(key, value);
  }

  Future<void> remove(String key) async => _box.remove(key);

  Future<void> clear() async => _box.erase();

  // 业务方法封装
  bool get isDarkMode => read<bool>('isDarkMode') ?? false;

  Future<void> setDarkMode(bool value) async {
    await write('isDarkMode', value);
  }

  String? get token => read<String>('token');

  Future<void> setToken(String token) async {
    await write('token', token);
  }

  Future<void> clearToken() async => remove('token');

  Map<String, dynamic>? get userInfo => read<Map<String, dynamic>>('userInfo');

  Future<void> setUserInfo(Map<String, dynamic> info) async {
    await write('userInfo', info);
  }
}

使用方式:

// 初始化
await Get.putAsync(() => StorageService().init());

// 读取
final storage = Get.find<StorageService>();
bool isDark = storage.isDarkMode;

// 写入
await storage.setDarkMode(true);

6. 结合 GetX 响应式

配合 GetxController 实现响应式存储:

class ThemeController extends GetxController {
  final _isDark = false.obs;

  bool get isDark => _isDark.value;

  final StorageService _storage = Get.find<StorageService>();

  @override
  void onInit() {
    super.onInit();
    _isDark.value = _storage.isDarkMode;
  }

  void toggleTheme() async {
    _isDark.value = !_isDark.value;
    await _storage.setDarkMode(_isDark.value);
    Get.changeThemeMode(_isDark.value ? ThemeMode.dark : ThemeMode.light);
  }
}

在页面中使用:

class SettingsPage extends StatelessWidget {
  final ThemeController themeCtrl = Get.find();

  @override
  Widget build(BuildContext context) {
    return Obx(() => Switch(
      value: themeCtrl.isDark,
      onChanged: (_) => themeCtrl.toggleTheme(),
    ));
  }
}

7. 实际项目示例:用户登录状态持久化

class AuthService extends GetxService {
  late final GetStorage _box;
  static const String _tokenKey = 'auth_token';
  static const String _userKey = 'user_info';

  Future<AuthService> init() async {
    _box = GetStorage();
    return this;
  }

  bool get isLoggedIn => _box.hasData(_tokenKey);

  String? get token => _box.read<String>(_tokenKey);

  Future<void> login(String token, Map<String, dynamic> user) async {
    await _box.write(_tokenKey, token);
    await _box.write(_userKey, user);
    // 触发登录状态更新
    Get.find<AuthController>().updateUser(user);
  }

  Future<void> logout() async {
    await _box.remove(_tokenKey);
    await _box.remove(_userKey);
    Get.find<AuthController>().clearUser();
  }
}

// 使用
class AuthController extends GetxController {
  final RxMap<String, dynamic> user = RxMap();

  void updateUser(Map<String, dynamic> info) {
    user.value = info;
  }

  void clearUser() {
    user.clear();
  }
}

8. 注意事项

8.1 数据类型

GetStorage 存储时会丢失 Dart 类型信息,读取 Map 时需要注意:

// 写入
await storage.write('data', {'count': 10});

// 读取后需要强制转换类型
Map<String, dynamic> data = storage.read<Map<String, dynamic>>('data') ?? {};
int count = data['count'] as int;  // 需要强制转换

8.2 加密存储

如需加密存储敏感数据:

await GetStorage.init(
  encryptionCipher: HiveCipher.withPassphrase('your_secure_password'),
);

8.3 异常处理

建议配合 try-catch 使用:

try {
  final data = _box.read<Map>('key');
  if (data != null) {
    // 处理数据
  }
} catch (e) {
  // 数据可能已损坏,清除并重新初始化
  await _box.remove('key');
}

9. 总结

  • GetStorage 适合简单键值对存储,与 GetX 无缝集成
  • 建议封装为 Service 统一管理存储逻辑
  • 配合 ObxObxBuilder 实现响应式数据持久化
  • 复杂数据结构建议使用 HiveSqflite

GetStorage 是 GetX 生态中最轻量的存储方案,非常适合快速原型和中小型项目。