引言:本地存储是开源鸿蒙应用的 “数据基石”

在开源鸿蒙(OpenHarmony)应用开发中,本地存储承担着 “数据持久化” 的核心角色 —— 保存用户登录状态、缓存配置偏好、离线数据等。一个优秀的本地存储方案,不仅要满足 “读写高效、安全可靠”,还要适配开源鸿蒙的分布式特性(如多设备数据同步、跨设备数据共享)。

本文将以 “场景化分类 + 实战落地” 为核心,从基础的SharedPreferences、文件存储,到进阶的数据库(Hive),再到开源鸿蒙特有的分布式存储,用 “原理 + 精简代码 + 对比选型” 的方式,带你掌握不同场景下的最优存储方案,所有代码块控制在 10 行内,确保易读易用。

一、先懂原理:开源鸿蒙本地存储的 3 类场景

根据数据类型和业务需求,开源鸿蒙 Flutter 应用的本地存储可分为 3 类场景:

场景类型 数据特点 推荐方案
轻量键值对 简单数据(如开关状态、用户 Token) SharedPreferences
复杂结构化数据 列表、对象(如商品列表、聊天记录) Hive 数据库
多设备共享数据 跨设备同步(如家庭清单、用户偏好) 鸿蒙分布式 KvStore

核心原则:根据数据复杂度和是否跨设备选择方案,避免 “大材小用” 或 “小材大用”。

二、基础实战 1:SharedPreferences—— 轻量键值对存储

SharedPreferences是 Flutter 生态中最常用的轻量存储方案,适用于保存简单的键值对数据,API 简洁,性能优秀。

2.1 环境配置

yaml

dependencies:
  shared_preferences: ^2.2.2

2.2 封装工具类(核心方法)

dart

import 'package:shared_preferences/shared_preferences.dart';

class SpUtil {
  static SharedPreferences? _prefs;
  // 初始化
  static Future<void> init() async => 
      _prefs = await SharedPreferences.getInstance();
  
  // 存储字符串(如Token)
  static Future<bool> setString(String key, String value) => 
      _prefs?.setString(key, value) ?? Future.value(false);
  
  // 获取字符串
  static String getString(String key, {String def = ""}) => 
      _prefs?.getString(key) ?? def;
  
  // 存储布尔值(如登录状态)
  static Future<bool> setBool(String key, bool value) => 
      _prefs?.setBool(key, value) ?? Future.value(false);
  
  // 获取布尔值
  static bool getBool(String key, {bool def = false}) => 
      _prefs?.getBool(key) ?? def;
}

2.3 实战场景

场景 1:保存用户登录状态

dart

// 登录成功后保存状态
Future<void> loginSuccess(String token) async {
  await SpUtil.setString('token', token);
  await SpUtil.setBool('isLogin', true);
}

// 启动时检查登录状态
void checkLoginStatus() {
  if (SpUtil.getBool('isLogin') && SpUtil.getString('token').isNotEmpty) {
    Navigator.pushReplacementNamed(context, '/home');
  } else {
    Navigator.pushReplacementNamed(context, '/login');
  }
}
场景 2:保存应用主题设置

dart

// 切换主题(浅色/深色)
Future<void> switchTheme(bool isDark) async => 
    await SpUtil.setBool('isDarkMode', isDark);

// 加载主题
bool loadTheme() => SpUtil.getBool('isDarkMode');

关键知识点

  • 所有存储操作都是异步的,需用await修饰;
  • 数据存储在应用沙盒中,安全性高,卸载应用会删除;
  • 不适合存储大量数据或复杂对象。

三、基础实战 2:文件存储 —— 二进制 / 大文件管理

当需要存储图片、音频等二进制文件,或大尺寸文本时,需使用 Flutter 的文件存储 API。

3.1 环境配置

yaml

dependencies:
  path_provider: ^2.1.1

3.2 核心工具方法

dart

import 'dart:io';
import 'package:path_provider/path_provider.dart';

class FileUtil {
  // 获取文档目录(私有,卸载删除)
  static Future<String> getDocPath() async => 
      (await getApplicationDocumentsDirectory()).path;
  
  // 获取缓存目录(可被系统清理)
  static Future<String> getCachePath() async => 
      (await getTemporaryDirectory()).path;
  
  // 保存文本文件
  static Future<File> saveText(String fileName, String content) async {
    final file = File('${await getDocPath()}/$fileName');
    return file.writeAsString(content);
  }
  
  // 保存二进制文件(如图片)
  static Future<File> saveBinary(String fileName, Uint8List data) async {
    final file = File('${await getCachePath()}/$fileName');
    return file.writeAsBytes(data);
  }
}

3.3 实战场景:保存用户头像

dart

// 下载并保存头像
Future<void> saveAvatar(String url, String userId) async {
  // 1. 下载图片数据(使用Dio)
  final response = await Dio().get<List<int>>(
    url, options: Options(responseType: ResponseType.bytes)
  );
  // 2. 保存到缓存目录
  await FileUtil.saveBinary('avatar_$userId.png', 
      Uint8List.fromList(response.data!));
}

// 加载本地头像
Future<File?> loadAvatar(String userId) async {
  final file = File('${await FileUtil.getCachePath()}/avatar_$userId.png');
  return file.exists() ? file : null;
}

关键知识点

  • 文档目录用于存储重要数据,缓存目录用于临时数据;
  • 开源鸿蒙应用只能访问自身沙盒目录,无法访问其他应用文件。

四、进阶实战:Hive 数据库 —— 复杂结构化数据存储

当需要存储列表、嵌套对象等复杂数据时,Hive 数据库是最优选择 —— 基于 NoSQL,无需原生依赖,性能优秀。

4.1 环境配置

yaml

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  hive_generator: ^1.1.5
  build_runner: ^2.4.4

4.2 定义 Hive 模型

dart

import 'package:hive/hive.dart';
part 'favorite_goods.g.dart'; // 自动生成

@HiveType(typeId: 0) // 唯一ID(0-223)
class FavoriteGoods extends HiveObject {
  @HiveField(0)
  final int id;

  @HiveField(1)
  final String name;

  @HiveField(2)
  final double price;

  FavoriteGoods({required this.id, required this.name, required this.price});
}

执行命令生成序列化代码:

bash

运行

flutter pub run build_runner build

4.3 初始化与核心操作

dart

// 初始化(main.dart)
Future<void> initHive() async {
  await Hive.initFlutter();
  Hive.registerAdapter(FavoriteGoodsAdapter());
  await Hive.openBox<FavoriteGoods>('favorites');
}

// 封装操作工具
class HiveUtil {
  static Box<FavoriteGoods> get _box => Hive.box<FavoriteGoods>('favorites');

  // 添加收藏
  static Future<void> addFavorite(FavoriteGoods goods) => 
      _box.put(goods.id, goods);

  // 移除收藏
  static Future<void> removeFavorite(int id) => _box.delete(id);

  // 获取所有收藏
  static List<FavoriteGoods> getFavorites() => _box.values.toList();
}

4.4 实战场景:商品收藏列表

dart

class FavoritePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('我的收藏')),
      body: ValueListenableBuilder<Box<FavoriteGoods>>(
        valueListenable: Hive.box<FavoriteGoods>('favorites').listenable(),
        builder: (context, box, _) {
          final favorites = box.values.toList();
          if (favorites.isEmpty) return const Center(child: Text('暂无收藏'));
          return ListView.builder(
            itemCount: favorites.length,
            itemBuilder: (_, i) => ListTile(
              title: Text(favorites[i].name),
              subtitle: Text('¥${favorites[i].price}'),
            ),
          );
        },
      ),
    );
  }
}

关键知识点

  • ValueListenableBuilder可监听数据库变化,实时更新 UI;
  • 按 ID 存储可避免重复数据;
  • 支持复杂对象存储,性能优于SharedPreferences

五、高阶实战:鸿蒙分布式 KvStore—— 多设备数据共享

开源鸿蒙的分布式 KvStore 是跨设备数据共享的核心方案,支持多设备实时同步,适用于家庭清单、用户偏好等场景。

5.1 原生端封装(Java)

java

运行

// DistributedKvStore.java
import ohos.data.distributed.common.KvStoreConfig;
import ohos.data.distributed.user.SingleKvStore;

public class DistributedKvStore {
    private static final String CHANNEL = "ohos.flutter/distributedKv";
    private SingleKvStore kvStore;

    public DistributedKvStore(Ability ability) {
        // 初始化分布式KvStore
        KvManager kvManager = KvManagerFactory.getInstance()
            .createKvManager(new KvManagerConfig(ability));
        kvStore = kvManager.getKvStore(
            new KvStoreConfig("appStore", KvStoreType.SINGLE_VERSION));
    }

    public void register(FlutterView flutterView) {
        new MethodChannel(flutterView, CHANNEL).setMethodCallHandler((call, result) -> {
            switch (call.method) {
                case "putString":
                    kvStore.putString(call.argument("key"), call.argument("value"));
                    result.success(true);
                    break;
                case "getString":
                    String value = kvStore.getString(call.argument("key"), "");
                    result.success(value);
                    break;
                default:
                    result.notImplemented();
            }
        });
    }
}

5.2 Flutter 端调用

dart

class DistributedStoreUtil {
  static const _channel = MethodChannel('ohos.flutter/distributedKv');

  // 保存数据到分布式存储
  static Future<bool> putString(String key, String value) async =>
      await _channel.invokeMethod('putString', {'key': key, 'value': value});

  // 从分布式存储获取数据
  static Future<String> getString(String key) async =>
      await _channel.invokeMethod('getString', {'key': key}) ?? "";
}

5.3 实战场景:家庭购物清单

dart

// 添加商品到清单(多设备同步)
Future<void> addShoppingItem(String item) async {
  // 1. 获取现有清单
  String listStr = await DistributedStoreUtil.getString('shoppingList');
  List<String> list = listStr.isEmpty ? [] : listStr.split(',');
  // 2. 添加新商品
  list.add(item);
  // 3. 保存回分布式存储
  await DistributedStoreUtil.putString('shoppingList', list.join(','));
}

// 加载购物清单(同步其他设备数据)
Future<List<String>> loadShoppingList() async {
  String listStr = await DistributedStoreUtil.getString('shoppingList');
  return listStr.isEmpty ? [] : listStr.split(',');
}

关键知识点

  • 分布式 KvStore 自动解决多设备数据冲突,优先保存最新数据;
  • 需在config.json中添加分布式权限(ohos.permission.DISTRIBUTED_DATASYNC);
  • 适合存储需要跨设备共享的轻量 / 中等复杂度数据。

六、存储方案选型指南(新手必看)

方案 适用场景 优点 缺点
SharedPreferences 轻量键值对(Token、开关状态) API 简洁、性能好、无需额外依赖 不支持复杂对象、大量数据
文件存储 二进制文件(图片、音频)、大文本 支持任意文件类型、存储容量大 需手动管理路径、不支持结构化查询
Hive 复杂结构化数据(列表、对象) 性能优秀、支持复杂对象、无原生依赖 需定义模型和序列化
分布式 KvStore 多设备共享数据(清单、偏好) 实时同步、跨设备访问、自动冲突解决 需鸿蒙原生支持、权限配置复杂

选型建议:

  1. 保存简单配置(如是否自动登录、主题模式)→ SharedPreferences
  2. 存储图片、音频等文件 → 文件存储;
  3. 存储本地清单、聊天记录等复杂数据 → Hive;
  4. 需多设备共享数据 → 分布式 KvStore。

七、常见问题(FAQ)

Q1:如何保证本地存储数据安全?

A1:敏感数据(如密码)可通过鸿蒙原生的加密 API 加密后再存储;普通数据使用默认存储即可(应用沙盒隔离,其他应用无法访问)。

Q2:Hive 数据库如何备份和恢复?

A2:可通过文件存储 API 备份 Hive 数据库文件(路径:getApplicationDocumentsDirectory()/hive),恢复时覆盖该目录即可。

Q3:分布式 KvStore 数据同步有延迟吗?

A3:延迟极低(毫秒级),在网络正常的情况下,多设备几乎实时同步;网络断开时,会在重连后自动同步。

结语:构建开源鸿蒙全场景存储体系

本地存储是开源鸿蒙应用的核心基础设施,选择合适的存储方案能让应用性能更优、用户体验更好。从基础的键值对存储到复杂的数据库,再到分布式共享,每种方案都有其适用场景,关键是根据业务需求合理选择。

通过本文的实战案例,你已经掌握了开源鸿蒙 Flutter 应用的 4 种核心存储方案,接下来可以根据项目需求灵活组合使用(如 Hive 存储本地数据,分布式 KvStore 同步关键信息),打造全场景适配的应用。

总结

  1. 开源鸿蒙 Flutter 本地存储主要有 4 种方案,分别适配不同场景;
  2. 轻量键值对用SharedPreferences,文件用文件存储,复杂数据用 Hive,跨设备共享用分布式 KvStore;
  3. 选型核心是 “匹配数据复杂度和业务需求”,避免过度设计。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐