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
- shared_preferences package trên Pub.dev