+27

Tìm hiểu về SharedPreferences trong Flutter: Lưu trữ dữ liệu cục bộ đơn giản

Sau khi đã nắm vững các kỹ thuật quản lý trạng thái để xử lý dữ liệu trong bộ nhớ (in-memory), chúng ta sẽ cần một phương pháp để lưu trữ dữ liệu bền vững, tức là dữ liệu không bị mất đi khi người dùng đóng ứng dụng. Đây là lúc lưu trữ dữ liệu cục bộ trở nên cần thiết.

Trong Flutter, một trong những cách đơn giản và phổ biến nhất để lưu trữ dữ liệu cục bộ là sử dụng package shared_preferences.


SharedPreferences là gì?

shared_preferences là một package Flutter cho phép chúng ta lưu trữ các cặp khóa-giá trị (key-value pairs) đơn giản trên thiết bị. Nó thường được dùng để lưu trữ:

  • Cài đặt người dùng: Chế độ sáng/tối, ngôn ngữ, tùy chọn thông báo.
  • Trạng thái ứng dụng nhỏ: Ví dụ, trạng thái "đã đăng nhập" của người dùng, hoặc lần đầu mở ứng dụng.
  • Dữ liệu nhỏ, không phức tạp: Ví dụ, điểm số cao trong một trò chơi, tên người dùng gần đây.

Về cơ bản, shared_preferences sử dụng các API lưu trữ nguyên bản của nền tảng:

  • iOS: NSUserDefaults
  • Android: SharedPreferences

Điều này có nghĩa là dữ liệu được lưu trữ một cách hiệu quả và an toàn theo cách mà hệ điều hành mong đợi.


Khi nào nên và không nên dùng SharedPreferences?

Nên dùng khi

  • Cần lưu trữ dữ liệu đơn giản, có kích thước nhỏ.
  • Dữ liệu dưới dạng cặp khóa-giá trị (String, int, bool, double, List<String>).
  • Dữ liệu không yêu cầu tính bảo mật cao (vì nó có thể dễ dàng được truy cập trên thiết bị).
  • Chỉ cần lưu trữ cấu hình hoặc tùy chọn của người dùng.

Không nên dùng khi:

  • Lưu trữ dữ liệu lớn hoặc phức tạp: Ví dụ: danh sách các đối tượng phức tạp, hình ảnh, video. Đối với trường hợp này, chúng ta nên xem xét cơ sở dữ liệu như SQLite, Hive, hoặc Isar.
  • Lưu trữ dữ liệu nhạy cảm, bảo mật cao: Mặc dù shared_preferences được lưu cục bộ, nó không được mã hóa mặc định và có thể bị truy cập bởi người dùng có kiến thức kỹ thuật. Đối với dữ liệu nhạy cảm (ví dụ: token bảo mật), chúng ta nên dùng các giải pháp lưu trữ an toàn hơn ví dụ như flutter_secure_storage. hoặc mã hóa thủ công trước khi lưu.
  • Lưu trữ dữ liệu cần tìm kiếm hoặc truy vấn phức tạp: shared_preferences không phải là một cơ sở dữ liệu; nó không hỗ trợ các truy vấn phức tạp.

Cài đặt

Để cài đặt shared_preferences chúng ta cần thêm thư viện vào trong file pubspec.yaml:

dependencies:
  shared_preferences: ^2.5.3

Sau khi thêm xong thì chúng ta chạy flutter pub get

Sử dụng shared_preferences

Trong file Dart mà chúng ta muốn sử dụng shared_preferences, hãy thêm dòng import:

import 'package:shared_preferences/shared_preferences.dart';

Lưu trữ dữ liệu (Ghi)

Để lưu trữ dữ liệu, chúng ta cần lấy một instance của SharedPreferences và sau đó sử dụng các phương thức set tương ứng. Các phương thức setBool, setInt, setDouble, setString, setStringList được sử dụng để lưu các loại dữ liệu khác nhau. Tất cả các phương thức này đều trả về một Future<bool>, cho biết thao tác có thành công hay không.

Future<void> saveData() async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();

  await prefs.setBool('isDarkMode', true);
  await prefs.setInt('userAge', 30);
  await prefs.setString('userName', 'Nguyen Van A');
  await prefs.setStringList('favoriteColors', ['red', 'green', 'blue']);

  print('Dữ liệu đã được lưu!');
}

Đọc dữ liệu

Các phương thức getBool, getInt, getDouble, getString, getStringList được sử dụng để đọc dữ liệu. Nếu khóa không tồn tại, chúng sẽ trả về null (hoặc giá trị mặc định của kiểu nếu không phải String hoặc List<String>).

Future<void> readData() async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();

  final bool? isDarkMode = prefs.getBool('isDarkMode');
  final int? userAge = prefs.getInt('userAge');
  final String? userName = prefs.getString('userName');
  final List<String>? favoriteColors = prefs.getStringList('favoriteColors');

  print('isDarkMode: $isDarkMode'); // Output: true
  print('userAge: $userAge');     // Output: 30
  print('userName: $userName');   // Output: Nguyen Van A
  print('favoriteColors: $favoriteColors'); // Output: [red, green, blue]

  // Lấy một khóa không tồn tại
  final String? nonExistentKey = prefs.getString('nonExistentKey');
  print('nonExistentKey: $nonExistentKey'); // Output: null
}

Xóa dữ liệu

  • remove(String key): Xóa một cặp khóa-giá trị cụ thể.
  • clear(): Xóa tất cả dữ liệu đã lưu trữ bởi ứng dụng.
Future<void> removeData() async {
  final SharedPreferences prefs = await SharedPreferences.getInstance();

  await prefs.remove('userAge'); // Xóa khóa 'userAge'
  print('Đã xóa userAge.');

  // Để xóa tất cả dữ liệu:
  // await prefs.clear();
  // print('Đã xóa tất cả dữ liệu.');
}

Ví dụ đầy đủ

Chúng ta cùng viết một app nhỏ: mỗi khi nhấn nút, số đếm sẽ tăng và vẫn được giữ nguyên khi mở lại ứng dụng.

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return const MaterialApp(home: CounterPage());
  }
}

class CounterPage extends StatefulWidget {
  const CounterPage({super.key});
  
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _counter = 0;

  
  void initState() {
    super.initState();
    _loadCounter(); // Load khi mở app
  }

  Future<void> _loadCounter() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      _counter = prefs.getInt('counter') ?? 0;
    });
  }

  Future<void> _incrementCounter() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      _counter++;
    });
    await prefs.setInt('counter', _counter); // Lưu lại
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SharedPreferences Demo')),
      body: Center(child: Text('Số lần bấm: $_counter', style: TextStyle(fontSize: 24))),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        child: const Icon(Icons.add),
      ),
    );
  }
}

Kết luận

SharedPreferences là lựa chọn tuyệt vời cho những nhu cầu lưu trữ đơn giản, không nhạy cảm trong ứng dụng Flutter. Nó nhẹ, dễ dùng và cực kỳ tiện lợi cho việc ghi nhớ trạng thái ứng dụng, tuỳ chỉnh của người dùng, hay logic đơn giản.

Trong các bài viết tiếp theo, chúng ta sẽ cùng tìm hiểu về những giải pháp lưu trữ mạnh mẽ hơn, chẳng hạn như Hive, SQLite hoặc flutter_secure_storage.

Cảm ơn các bạn đã theo dõi. Chúc các bạn học tập hiệu quả. Nếu bài viết có sai sót hoặc chưa rõ ràng ở đâu xin các bạn hãy để lại một cmt để mình biết nhé.


Tham khảo


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí