Day 17: Giving Your App a Memory
An app that forgets everything when you close it isn’t very smart. Today, we’ll go beyond the basics and truly understand how to give our app a reliable memory using local storage.
Why Does an App Need a Memory?
Imagine you’ve customized your favorite weather app: you’ve set your home city to Lahore, chosen Celsius over Fahrenheit, and enabled severe weather alerts. You close the app and open it an hour later to find it has reset completely—it thinks you’re in Karachi, shows Fahrenheit, and all your alerts are off. Infuriating, right? That’s an app with amnesia.
Local storage is the part of the app’s “brain” that lives on the user’s device. It’s what allows the app to remember information between sessions, creating a persistent and personalized experience. Today, we’ll master the two fundamental tools Flutter gives us for this: one for quick, simple “sticky notes” (`shared_preferences`) and another for finding the “filing cabinet” to store larger files (`path_provider`).
The Filing Cabinet Assistant: `path_provider`
When sticky notes aren’t enough and you need to save an actual file—like a downloaded PDF, a user-created drawing, or a JSON log file—you need a filing cabinet. The problem is, the location of this cabinet is different on every operating system. You can’t just save a file to `C:\Users\MyStuff` because that path doesn’t exist on iOS or Android.
This is where `path_provider` becomes essential. Crucially, `path_provider` does NOT save any data. It’s an assistant that simply tells you the correct, platform-specific *address* (the file path) where you’re allowed to store certain types of files. Once you have that address, you use other tools (like `dart:io`) to actually create and write to the file.
Live Simulation: Finding Storage Locations
Find a Directory:
Click a button to see typical file paths and their purpose.
The Code Explained:
import 'package:path_provider/path_provider.dart';
import 'dart:io'; // Needed to use the File class
// For files the user generates that should be kept.
_getDocsPath() async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
// For temporary cache files the OS can delete.
_getTempPath() async {
final directory = await getTemporaryDirectory();
return directory.path;
}
// How you'd use it to save a file:
_saveLogFile() async {
// 1. Get the path from the provider.
final path = await _getDocsPath();
// 2. Create a File object at that location.
final file = File('$path/user_log.txt');
// 3. Write to the file using dart:io.
await file.writeAsString('User logged in at ${DateTime.now()}');
}
Which One Should I Use? A Quick Guide
It can be confusing at first. Here’s a simple cheat sheet to help you decide which tool is right for the job.
Feature | `shared_preferences` | `path_provider` + `dart:io` |
---|---|---|
Analogy | 📝 Sticky Notes | 🗄️ Filing Cabinet |
Data Type | Simple key-value pairs (String, bool, int, double) | Any kind of file (text, JSON, images, PDF, etc.) |
Data Size | Small (a few KBs) | Small to very large (MBs or GBs) |
Primary Use Case | Storing user settings and simple flags. | Saving user-generated content or large cached data. |
Example | `prefs.setBool(‘darkMode’, true);` | `File(‘$path/profile.jpg’).writeAsBytes(…)` |