Data Persistence in Flutter
Data persistence is an essential aspect of any mobile application. It involves storing and retrieving data even after the application is closed or the device is restarted. In Flutter, data persistence can be achieved using various methods, including secured local storage and API calls. In this article, we’ll explore these two methods and show you how to implement them in your Flutter app.
Local Storage
Storing data in local storage is a popular method for data persistence in mobile applications. Local storage refers to the storage space available on the device where data can be stored and retrieved. In Flutter, local storage can be implemented using the shared_preferences package. This package provides a simple way to store key-value pairs in local storage.
To use the shared_preferences package, add it to your dependencies in the pubspec.yaml file as follows:
dependencies:
shared_preferences: ^2.0.8
Once you have added the package to your dependencies, you can use it to store and retrieve data from local storage. For instance, consider the following example where we want to store and retrieve a user’s name:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String _name = '';
@override
void initState() {
super.initState();
_loadName();
}
Future<void> _loadName() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_name = prefs.getString('name') ?? '';
});
}
Future<void> _saveName(String name) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_name = name;
});
await prefs.setString('name', name);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Data Persistence in Flutter'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Hello $_name!'),
TextField(
decoration: InputDecoration(
hintText: 'Enter your name',
),
onSubmitted: (String value) {
_saveName(value);
},
),
],
),
);
}
}
In the above code, we have defined two methods – _loadName and _saveName. _loadName loads the user’s name from local storage, while _saveName saves the user’s name to local storage.
When the app is launched, the _loadName method is called in the initState method. This method loads the user’s name from local storage using the SharedPreferences.getInstance() method. If the user’s name is not found in local storage, the default value of an empty string is used.
When the user enters their name in the TextField widget and submits it, the _saveName method is called. This method saves the user’s name to local storage using the prefs.setString(‘name’, name) method.
In this way, the user’s name is persisted in local storage even after the app is closed or the device is restarted. The next time the user launches the app, their name will be loaded from local storage and displayed on the screen.
Minimizing API Calls
Another way to achieve data persistence in Flutter is to minimize API calls. API calls refer to the process of retrieving data from a server using an API. Minimizing API calls involves reducing the number of times data is retrieved from the server, which can improve app performance and reduce data usage.
One way to minimize API calls is to cache data locally. Caching involves storing data in local storage for a certain period of time and retrieving it from local storage instead of making an API call every time the data is needed.
In Flutter, caching can be implemented using the flutter_cache_manager package. This package provides a cache manager that can be used to store and retrieve data from local storage.
To use the flutter_cache_manager package, add it to your dependencies in the pubspec.yaml file as follows:
dependencies:
flutter_cache_manager: ^3.1.2
Once you have added the package to your dependencies, you can use it to cache data. For instance, consider the following example where we want to cache a list of posts retrieved from an API:
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<dynamic> _posts = [];
@override
void initState() {
super.initState();
_loadPosts();
}
Future<void> _loadPosts() async {
var cacheManager = await CacheManager.getInstance();
var file = await cacheManager.getFile('https://jsonplaceholder.typicode.com/posts');
if (file != null && await file.exists()) {
// Read data from cache
var jsonString = await file.readAsString();
var data = jsonDecode(jsonString);
setState(() {
_posts = data;
});
} else {
// Make API call
var response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
// Cache data
await cacheManager.putFile('https://jsonplaceholder.typicode.com/posts', response.bodyBytes);
var data = jsonDecode(response.body);
setState(() {
_posts = data;
});
} else {
throw Exception('Failed to load posts');
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Data Persistence in Flutter'),
),
body: ListView.builder(
itemCount: _posts.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_posts[index]['title']),
subtitle: Text(_posts[index]['body']),
);
},
),
);
}
}
In the above code, we have defined a _loadPosts method that retrieves a list of posts from an API. This method first checks if the data is available in local storage using the cacheManager.getFile() method. If the data is available in local storage, it is loaded from the cache and displayed on the screen. If the data is not available in local storage, an API call is made using the http.get() method. The data retrieved from the API is then cached using the cacheManager.putFile() method.
In this way, the data is retrieved from the server only when it is not available in local storage. Once the data is retrieved, it is cached in local storage for a certain period of time, reducing the number of API calls made by the app.
Conclusion
Data persistence is an essential aspect of any mobile application. In Flutter, data persistence can be achieved using various methods, including secured local storage and API calls. Secured local storage can be implemented using the shared_preferences package, while caching can be implemented using the flutter_cache_manager package. By implementing these methods, you can ensure that your app performs efficiently and provides a better user experience. Additionally, by using secure local storage, you can protect user data from unauthorized access and ensure their privacy.
Overall, data persistence is a critical consideration for any mobile application. By using secure local storage and caching data, you can reduce the number of API calls made by your app, improve its performance, and provide a better user experience for your users. With Flutter, it is easy to implement data persistence in your app and ensure that your users’ data is protected and accessible when needed.