Flutter本地数据存储插件local_value的使用

发布于 1周前 作者 caililin 来自 Flutter

Flutter本地数据存储插件local_value的使用

Flutter应用开发中,数据持久化是必不可少的一环。无论是保存用户偏好设置、缓存网络请求结果还是保存应用程序状态,都离不开对本地数据的操作。local_value 是一个用于Flutter项目的本地数据存储插件,它提供了简单且类型安全的方式来读取、写入和删除本地数据。下面将详细介绍如何使用这个插件,并提供完整的示例代码。

Quickstart 快速开始

单例模式保存

// 保存单个值到本地
final localCounterValue = LocalSingleton<int>(id: 'counter_val');
await localCounterValue.write(5);
print(await localCounterValue.read()); // 输出:5

多对象保存

// 保存多个相关对象
final localUserScores = LocalValue<int>(basePath: ['user_scores']);
await localUserScores.write('user_1', 15); 
await localUserScores.write('user_2', 24);

print(await localUserScores.read('user_1')); // 输出:15
print(await localUserScores.read('user_2')); // 输出:24

Features 功能特性

  • 支持保存/加载/删除单例到本地存储。
  • 可以指定文档类型为应用文档、临时文档、支持文件或共享偏好设置。具体区别可以参考 path_provider 文档。
  • Web平台使用 shared_preferences 实现后台存储,因为Web端没有文件系统的概念。

文档类型说明

  • DocumentType.document: 用户生成的数据,无法重新创建(例如:本地游戏中的最高分)。
  • DocumentType.support: 非用户生成的数据,无法重新创建(例如:自动配置文件)。
  • DocumentType.temporary: 可以随时清除的数据(例如:缓存下载的JSON)。
  • DocumentType.secure: 必须安全存储的数据(例如:用户的API密钥)。
  • DocumentType.prefs: 用户偏好设置(例如:是否以浅色模式打开应用)。

Use cases 使用场景

登录用户信息保存

class CurrentUser {
    final int id;
    final String name;
    final Color favoriteColor;

    // 添加 toJson 和 fromJson 方法
}

final locallyPersistedUser = localSingleton<CurrentUser>(
      id: 'current_user',
      fromJson: CurrentUser.fromJson,
      toJson: (currentUser) => currentUser.toJson());

// 保存和加载用户信息
CurrentUser? myCurrentUser = await locallyPersistedUser.read();
await locallyPersistedUser.write(someUser);

缓存避免重复网络请求

final localUsers = LocalValue<User>(toJson: ..., fromJson: ...);
await localUsers.read(userOneId);
await localUsers.write(userTwoId, userTwo);

类型安全地保存偏好设置

final isDarkMode = LocalSingleton<bool>(documentType: DocumentType.prefs, id: 'isDarkMode');
await isDarkMode.write(true);
final darkMode = await isDarkMode.read() ?? false;

LocalValue vs LocalSingleton

该包暴露了 LocalValueLocalSingleton 两个类。它们具有非常相似的API,但有一个关键区别:LocalSingleton 总是保存到同一个文件中,适用于只需要存储一个值的情况,如当前用户的数据;而 LocalValue 则需要在读取、写入和删除时提供一个 id 参数,适合存储多个用户的数据。

Usage 示例用法

创建并操作本地存储对象

import 'package:local_value/local_value.dart';

class CounterObj {
  int value;
  CounterObj(this.value);
}

// 创建本地存储实例
final counterFile = localSingleton<CounterObj>(
  documentType: DocumentType.document,
  id: 'counter',
  fromJson: (counterJson) => CounterObj(counterJson['value'] as int),
  toJson: (counterObj) => {'value': counterObj.value}
);

// 从本地读取
CounterObj? myCurrentCounter = await counterFile.read();

// 写入本地
await counterFile.write(myCurrentCounter ?? CounterObj(8));

// 清除本地存储
await counterFile.clear();

完整示例Demo

以下是一个完整的Flutter项目示例,展示了如何结合 local_value 插件实现计数器功能,并将计数结果保存到本地。

import 'package:flutter/material.dart';
import 'package:local_value/local_value.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final counterStorage = LocalSingleton<int>(id: 'counter');

  MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Local Data Manager Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      floatingActionButton: Builder(
        builder: (context) => Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            FloatingActionButton(
              onPressed: () async {
                final value = await widget.counterStorage.read();
                if (value == null) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(content: Text('no local data saved')),
                  );
                  return;
                }
                setState(() {
                  _counter = value;
                });
              },
              backgroundColor: Colors.orange,
              child: const Icon(Icons.replay),
            ),
            FloatingActionButton(
              onPressed: () async {
                await widget.counterStorage.write(_counter);
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text('saved!')),
                );
              },
              backgroundColor: Colors.green,
              child: const Icon(Icons.save),
            ),
            FloatingActionButton(
              onPressed: _incrementCounter,
              child: const Icon(Icons.add),
            ),
          ],
        ),
      ),
    );
  }
}

此示例创建了一个简单的计数器应用,用户可以通过点击按钮增加计数器的值,并可以选择保存当前计数值到本地或者从本地恢复计数值。通过这种方式,即使应用程序关闭后重新启动,也可以保留之前的计数状态。

Additional information 其他信息

如果您在使用过程中遇到任何问题,请前往GitHub提交Issue。作者正在积极维护这个包,并欢迎提出功能需求。由于该包基于两个经过充分测试的底层库 (shared_preferencespath_provider) 构建,因此整体稳定性较高。


更多关于Flutter本地数据存储插件local_value的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter本地数据存储插件local_value的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter应用中使用local_value插件进行本地数据存储的示例代码。local_value是一个简化版的本地存储插件,尽管它不如一些更流行的插件(如shared_preferences)那样广泛使用,但原理是类似的。需要注意的是,由于local_value不是一个实际存在的Flutter插件名称(可能是一个假设或打字错误,常见的类似插件是shared_preferenceslocalstorage),以下示例将基于一个假设的API结构来演示。

首先,确保在你的pubspec.yaml文件中添加了local_value(假设的)依赖项:

dependencies:
  flutter:
    sdk: flutter
  local_value: ^1.0.0  # 假设的版本号

然后,运行flutter pub get来安装依赖项。

接下来,在你的Flutter项目中,你可以按照以下方式使用local_value插件进行数据存储和检索:

import 'package:flutter/material.dart';
import 'package:local_value/local_value.dart';  // 假设的导入路径

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Local Value Demo'),
        ),
        body: Center(
          child: LocalValueDemo(),
        ),
      ),
    );
  }
}

class LocalValueDemo extends StatefulWidget {
  @override
  _LocalValueDemoState createState() => _LocalValueDemoState();
}

class _LocalValueDemoState extends State<LocalValueDemo> {
  String? _savedValue;
  final LocalValue _localValue = LocalValue();  // 假设的实例化方式

  @override
  void initState() {
    super.initState();
    // 从本地存储中检索数据
    _retrieveData();
  }

  Future<void> _retrieveData() async {
    String? value = await _localValue.getString('my_key');
    if (value != null) {
      setState(() {
        _savedValue = value;
      });
    }
  }

  Future<void> _saveData(String value) async {
    await _localValue.setString('my_key', value);
    setState(() {
      _savedValue = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text(
          'Saved Value:',
          style: TextStyle(fontSize: 20),
        ),
        Text(
          _savedValue ?? 'No value saved',
          style: TextStyle(fontSize: 20),
        ),
        SizedBox(height: 20),
        TextField(
          decoration: InputDecoration(labelText: 'Enter new value'),
          onSubmitted: (value) {
            _saveData(value);
          },
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: () async {
            await _saveData(_savedValue ?? '');  // 重新保存当前值或空字符串
          },
          child: Text('Save'),
        ),
      ],
    );
  }
}

注意

  1. 上述代码是基于一个假设的local_value插件API编写的。如果local_value实际上不存在,你可能需要使用shared_preferences或其他类似的插件。
  2. LocalValue类及其方法(如getStringsetString)是假设的。你需要根据实际的插件API文档进行调整。
  3. 对于shared_preferences插件,其使用方式非常类似,只是你需要导入package:shared_preferences/shared_preferences.dart,并且使用SharedPreferences.getInstance()来获取实例,然后调用setStringgetString方法。

如果你实际使用的是shared_preferences,请参考以下代码:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Shared Preferences Demo'),
        ),
        body: Center(
          child: SharedPreferencesDemo(),
        ),
      ),
    );
  }
}

class SharedPreferencesDemo extends StatefulWidget {
  @override
  _SharedPreferencesDemoState createState() => _SharedPreferencesDemoState();
}

class _SharedPreferencesDemoState extends State<SharedPreferencesDemo> {
  String? _savedValue;
  late SharedPreferences _preferences;

  @override
  void initState() {
    super.initState();
    _loadPreferences();
  }

  Future<void> _loadPreferences() async {
    _preferences = await SharedPreferences.getInstance();
    String? value = _preferences.getString('my_key');
    if (value != null) {
      setState(() {
        _savedValue = value;
      });
    }
  }

  Future<void> _savePreferences(String value) async {
    await _preferences.setString('my_key', value);
    setState(() {
      _savedValue = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text(
          'Saved Value:',
          style: TextStyle(fontSize: 20),
        ),
        Text(
          _savedValue ?? 'No value saved',
          style: TextStyle(fontSize: 20),
        ),
        SizedBox(height: 20),
        TextField(
          decoration: InputDecoration(labelText: 'Enter new value'),
          onSubmitted: (value) {
            _savePreferences(value);
          },
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: () async {
            await _savePreferences(_savedValue ?? '');
          },
          child: Text('Save'),
        ),
      ],
    );
  }
}

这段代码演示了如何使用shared_preferences插件在Flutter应用中进行本地数据存储和检索。

回到顶部